Categories
React Tips

React Tips — Sharing Data

Spread the love

React is a popular library for creating web apps and mobile apps.

In this article, we’ll look at some tips for writing better React apps.

Update React Context from Inside a Child Component

We can update the React context by first creating a context, and wrapping the child component in the context consumer.

Then we can use the function returned by the useContext hook in the child component to do the update.

For instance,e we can write:

const NameContext = React.createContext({
  name: "",
  setName: () => {}
});

const NameSwitcher = () => {
  const { name, setName } = useContext(NameContext);
  return (
    <button onClick={() => setName("mary")}>
      change name
    </button>
  );
};

const App = () => {
  const [name, setName] = useState("");

  return (
    <NameContext.Provider value={{ name, setName }}>
      <h2>Name: {name}</h2>
      <div>
        <NameSwitcher />
      </div>
    </NameContext.Provider>
  );
};

First, we create the NameContext with the React.createContext method.

Then, we have the App component, which has the name state and setName to update the name state.

We then have the NameContext.Provider wrapped around all the component that we want to have access to NameContext .

The nesting can be at any level.

Everything in the value prop will be returned by useContext when we use it.

Therefore, in NameSwitcher , we can use the setName function to set the name state, which is also returned by useContext .

In class components, we can do the same thing.

For instance, we can write:

const NameContext = React.createContext({
  name: "",
  setName: () => {}
});

class NameSwitcher extends Component {
  render() {
    return (
      <NameContext.Consumer>
        {({ name, setName }) => (
          <button onClick={() => setName("mary")}>
            change name
          </button>
        )}
      </NameContext.Consumer>
    );
  }
}

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      language: "en",
      setLanguage: this.setLanguage
    };
    this.setName = this.setName.bind(this);
  }

  setName(name) {
    this.setState({ name });
  };

  render() {
    return (
      <NameContext.Provider value={{
        name: this.state.name,
        setName: this.setName
      }}>
        <h2>Name: {name}</h2>
        <div>
          <NameSwitcher />
        </div>
      </NameContext.Provider>
    );
  }
}

We have the same context object, but the state change functions, and the states are at different places.

We pass them into the value prop in on the object.

Since we passed them into the value prop’s object, we can access them in NameSwitcher .

The only difference is that we need to add a NameContext.Consumer and a callback inside it to access the properties.

They’re in the parameter of the callback.

Difference Between useCallback and useMemo

We use useMemo to memoize a calculation result a function’s calls and renders.

useCallback is for memoizing a callback itself between renders.

The reference is cached.

useRef is to keep data between renders.

useState does the same.

Therefore, we can use useMemo to avoid heavy calculations.

useCallback fixes performance issues where inline handlers cause a PureComponent ‘s child to render again.

This happens because function expressions are different referentially each time they render.

Make Ajax Request in Redux

We can make Ajax requests with Redux if we use the Redux Thunk middleware.

To install it, we run:

npm install redux-thunk

To use it, we write:

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';

const store = createStore(rootReducer, applyMiddleware(thunk));

We import the rootReducer and the thunk middleware.

And we call applyMiddleware to apply the thunk middleware.

Now we can create our own thunk by writing:

const fetchUsers = () => {
  return dispatch => {
     fetch(`https://randomuser.me/api/`)
       .then(res => res.json())
       .then(res => {
          dispatch(saveUserData(res))
       })
   }
}

store
  .dispatch(fetchUsers())
  .then(() => {
    //...
  })

We pass a function that has the dispatch parameter, which is the Redux dispatch function, into the store.dispatch method.

The dispatch parameter is called to put the data into the Redux store.

Then to map this function to our component’s props, we can write:

function mapDispatchToProps(dispatch) {
  return {
    fetchUsers: () => dispatch(fetchUsers()),
  };
}

Now we can call this.prop.fetchUsers to call dispatch our async action.

fetchUsers is an action creator function, but it’s async.

It can be so thanks to the Redux Thunk plugin.

Conclusion

We can use the context API to share data with class and function components.

If we want a more flexible way to share data, we can use Redux with Redux Thunk.

This lets us set data in an async manner.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *