Code Monkey home page Code Monkey logo

use-url-state's Introduction

with-url-state

CircleCI codecov Npm

Lifts the state out of a react component and into the url

color-example

Hooks

There is a hook based api available on the 3.0.0 branch, published as a beta on npm.

Installation

To install with npm use

npm install with-url-state --save

To install with yarn use

yarn add with-url-state

Usage

Check out the the demo view the code or play with it in CodeSandbox.

Using javascript

import React from 'react'
import { withUrlState } from 'with-url-state'

const enhance = withUrlState(props => ({ color: 'blue' }))

export const UrlForm = enhance(props => (
  <div className="UrlForm">
    <div className="current-state" style={{ backgroundColor: props.urlState.color }}>
      <div>{props.urlState.color}</div>
    </div>
    <div className="color-buttons">
      <button className="Red" onClick={() => props.setUrlState({ color: 'red' })}>
        Red
      </button>
      <button className="Green" onClick={() => props.setUrlState({ color: 'green' })}>
        Green
      </button>
      <button className="Blue" onClick={() => props.setUrlState({ color: 'blue' })}>
        Blue
      </button>
    </div>
  </div>
))

Using typescript

import React from 'react'
import { withUrlState, UrlStateProps } from 'with-url-state'

type OwnProps = {}
type UrlState = { color: string }

const enhance = withUrlState<UrlState, OwnProps>((prop: OwnProps) => ({ color: 'blue' }))

export const UrlForm = enhance((props: OwnProps & UrlStateProps<UrlState>) => (
  <div className="UrlForm">
    <div className="current-state" style={{ backgroundColor: props.urlState.color }}>
      <div>{props.urlState.color}</div>
    </div>
    <div className="color-buttons">
      <button className="Red" onClick={() => props.setUrlState({ color: 'red' })}>
        Red
      </button>
      <button className="Green" onClick={() => props.setUrlState({ color: 'green' })}>
        Green
      </button>
      <button className="Blue" onClick={() => props.setUrlState({ color: 'blue' })}>
        Blue
      </button>
    </div>
  </div>
))

Using the render-prop component

import React from 'react'
import { UrlState } from 'with-url-state'

type OwnProps = {}
type UrlState = { color: string }

export const UrlForm = (props: OwnProps) => (
  <UrlState
    initialState={{ color: 'green' }}
    render={({ setUrlState, urlState }) => (
      <div className="UrlForm">
        <div className="current-state" style={{ backgroundColor: urlState.color }}>
          <div>{urlState.color}</div>
        </div>
        <div className="color-buttons">
          <button className="Red" onClick={() => setUrlState({ color: 'red' })}>
            Red
          </button>
          <button className="Green" onClick={() => setUrlState({ color: 'green' })}>
            Green
          </button>
          <button className="Blue" onClick={() => setUrlState({ color: 'blue' })}>
            Blue
          </button>
        </div>
      </div>
    )}
  />
)

Motivation

with-url-state automates the query parameter manipulations, simplifying URL sharing for search results, querying data or tracking a visible portion of a map.

The api provided is:

  • based on higer-order-components which makes it composable and testable
  • has a render-prop alternative for convenience
  • type-safe thanks to Typescript
  • very similar to Reacts built in state apis, so converting a component which already manages state is usually as simple as replacing setState with setUrlState!

Pollyfill

For use in IE11 you will need https://github.com/kumarharsh/custom-event-polyfill and add import 'custom-event-polyfill'; if (typeof Event !== 'function') { window.Event = CustomEvent; } to the upper scope of your application.

use-url-state's People

Contributors

carlosfromnewyork avatar crusectrl avatar dean177 avatar dependabot[bot] avatar greenkeeper[bot] avatar greenkeeperio-bot avatar henriquelange avatar mghawes avatar mountainstar avatar newyork-anthonyng avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

use-url-state's Issues

Clear state from URL when empty/undefined/null

Is there a way to clear the state from the URL when it's empty? For example, in a project I'm currently working on the URL often ends up looking like ?archive=false&search=&month= when I would like it to be just ?archive=false. Is this possible using this library?

I'm using the beta version with the useUrlState hook.

Change in v3 - clearing parameters from URL clears them from the state

If you're at /wherever?animal=ant and you navigate to /wherever?, in v3 you are given {} as the URL state - IE the value is completely removed from the state.

In v2, you'd still get a value in the state. It's happening just because of how setState no longer accepts Partial<T> anymore. In v2, React would just treat it as a partial state update so you'd get back the previous values.

I had started putting in a fix but realised it's not actually clear what the ideal behaviour is here. I think I'd actually expect to get nothing back from the state, ie the new behaviour is correct, but I can see arguments both ways.

I'm guessing this wasn't an intentional change - thoughts?

Confusion around initialState

Currently the API fixes the state you pass in, but it means the demo can't just load the page with ?color=red; it always gets wiped to blue. I'd assume bookmarking state is the goal here, right?

So ideally you'd be giving the component default values to apply if missing from the query. Right now to apply defaults you have to leave them out of the initial state and make your own function wrapper that reads props and applies the default.

Getting "window is not defined" when using custom history on SSR application

I'm instantiating a new withUrlState component using a custom history inside the config parameter, as described on the changelog.

The application has a NextJS SSR implementation, though not supporting browser components. When the method executes, it throws the following:

ReferenceError: window is not defined
    at Object.<anonymous> (/node_modules/with-url-state/dist/withUrlState.js:24:15)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)
    at Function.Module._load (module.js:498:3)
    at Module.require (module.js:597:17)
    at require (internal/module.js:11:18)
    at Object.with-url-state (/.next/dist/bundles/pages/_error.js:53158:18)

As I checked, apparently this error is being thrown because the html5HistoryAdapter location property export calls window.location independently of the config object passed on the constructor:

exports.html5HistoryAdapter = {
    listen: function (listener) {
        window.addEventListener('popstate', listener);
        return function () { return window.removeEventListener('popstate', listener); };
    },
    location: window.location,
    push: function (_a) {
        var search = _a.search;
        window.history.pushState(window.history.state, document.title, search);
        window.dispatchEvent(new window.Event('popstate'));
    },
    replace: function (_a) {
        var search = _a.search;
        window.history.replaceState(window.history.state, document.title, search);
        window.dispatchEvent(new window.Event('popstate'));
    },
};

Could you, please, take a look at this?

The order of Props and State in inconsistent between the readme and the code

In the readme we have the following line:

const enhance = withUrlState<OwnProps, UrlState>((prop: OwnProps) => ({ color: 'blue' }))

But in /src/withUrlState.ts we have

export const withUrlState = <T extends object, OP>(
  getInitialState: (props: OP) => T,

getInitialState maps the props to the state, so OP is the Props and T is the State

It would be nicest to swap the order of the props, so that it can be used with withUrlState<UrlState, OwnProps> to match the order of a standard React component. But since that would break a few builds, the readme should at least be updated to reflect this.

Hooks?

Any chance the v3 branch could be released if it's ready to go?

Cheers

Suggestion: Use the state to be pushed instead of what is called by setUrlState

https://github.com/Dean177/with-url-state/blob/a6d1250eaba7cb97863159a7ea62f025c891131a/src/withUrlState.ts#L127

config &&
config.shouldPushState &&
config.shouldPushState(this.props, newState, parse(this.state.previousSearch))
 ? history.push(nextLocation)
 : history.replace(nextLocation)

@Dean177 Might be better to have shouldPushState called with the merge of newState and currentState otherwise it's a bit hard to compare them.
Example: Suppose your state is { a: 1, b: 2 } and you call setUrlState({ a: 3 }). I would expect a call of:

shouldPushState(props, { a: 3, b: 2 }, { a: 1, b: 2 })

not

shouldPushState(props, { a: 3 }, { a: 1, b: 2 })

Thoughts?

I can obviously work around this if you think that's a worse API but I reckon it makes sense. At the very least if we keep it the same we should rename newState to something like stateUpdate or something. I don't mind making a quick PR?

Warn the users who have sensitive info in their state

Good job. Just a security concern:

Redux promotes single state and ask too often people store sensitive info like credentials or tokens in it. There needs to be a way to opt-out part of the state or opt-in relevant parts. A reducer that takes state and generates JSON for this lib can do both.
Nevertheless it's good to warm the users of this lib puts the whole state in the url.

An in-range update of query-string is breaking the build 🚨

The dependency query-string was updated from 6.1.0 to 6.2.0.

🚨 View failing branch.

This version is covered by your current version range and after updating it in your project the build failed.

query-string is a direct dependency of this project, and it is very likely causing it to break. If other packages depend on yours, this update is probably also breaking those in turn.

Status Details
  • ❌ ci/circleci: Your tests failed on CircleCI (Details).

Commits

The new version differs by 8 commits.

  • eda1fdc 6.2.0
  • f0b7db4 Meta tweaks
  • b20493e Do not sort when sort option is set to false (#155)
  • 5b4ce87 Support hash in parseUrl() (#151)
  • ff8eef3 Add readme note about create-react-app (#156)
  • 006f019 Bump fast-check version and adapt properties (#154)
  • b4dee48 Fix lint error (#149)
  • 61fbada Fix failing tests in Node 10 caused by wrong sort option type (#142)

See the full diff

FAQ and help

There is a collection of frequently asked questions. If those don’t help, you can always ask the humans behind Greenkeeper.


Your Greenkeeper Bot 🌴

Demo link is broken

Thank you for this project πŸ‘

I wanted to play around with the demo and noticed the link was broken (https://dean177.github.io/with-url-state/).

I'm wondering if including a CodeSandbox example would be helpful as well. This way, users can edit the code and play around with it as well.

I could create a CodeSandbox with the example from this repository. Let me know what you think; I can create a Pull Request to include it in the README.md.

Validation/defaults

While of course we can have a function to read props to validate, etc., it might be cleaner to allow declaring expected names/validators/defaults so you have control over what can get into props. Just an idea.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.