Passing a function with React Context API to child component nested deep in the tree
31,503
Maybe something like that?
<Context.Provider
value={{
state: this.state,
onSortClient: this.onSortClient,
}}
>
{this.props.children}
</Context.Provider>
So, value.state
will be your state, value.onSortClient
will be your function.
Author by
acd37
Updated on July 09, 2022Comments
-
acd37 almost 2 years
I'm using React Context API for the first time. I have a table that generates a list of clients. Originally, I stored the clients in an array in state, and in the same page I had a function that sorted the clients based on click.
I have moved the clients into context rather than in state of the actual page where the table is, but now of course my sort function no longer works. What I need to be able to do is use the same function, but organize the array that is in the context state instead.
Original function:
onSortClient = column => e => { const direction = this.state.sort.column ? this.state.sort.direction === "asc" ? "desc" : "asc" : "desc"; const sortedData = this.state.clients.sort((a, b) => { if (column === "client_name") { const nameA = a.client_name.toUpperCase(); const nameB = b.client_name.toUpperCase(); if (nameA < nameB) { return -1; } if (nameA > nameB) { return 1; } return 0; } return 0; }); if (direction === "desc") { sortedData.reverse(); } this.setState({ clients: sortedData, sort: { column, direction } }); };
My context file:
import React, { Component } from "react"; import axios from "axios"; const Context = React.createContext(); const Reducer = (state, action) => { switch (action.type) { case "DELETE_CLIENT": console.log(action.payload); return { ...state, clients: state.clients.filter(client => client.id !== action.payload) }; case "ADD_CLIENT": return { ...state, clients: [action.payload, ...state.clients] }; case "UPDATE_CLIENT": console.log(action.payload); return { ...state, clients: state.clients.map( client => client.id === action.payload.id ? (client = action.payload) : client ) }; default: return state; } }; export class Provider extends Component { state = { clients: [], loaded: false, dispatch: action => { this.setState(state => Reducer(state, action)); } }; async componentDidMount() { let localToken = localStorage.getItem("iod_tkn"); const res = await axios({ url: "/users/get_clients", method: "get", headers: { Authorization: localToken } }); this.setState({ clients: res.data, loaded: true }); } render() { return ( <Context.Provider onSortClient={this.onSortClient} value={this.state}> {this.props.children} </Context.Provider> ); } } export const Consumer = Context.Consumer;
-
acd37 over 5 yearsIf you're pretty good at React, I have another question that nobody has been able to solve yet :) stackoverflow.com/questions/51994498/…
-
user2918201 over 2 yearsI feel it necessary to point out that if you use this code as is, every component that consumes this state will re-render every time this component re-renders. This is because you are creating a new object to pass to
value
every time this renders. See: reactjs.org/docs/context.html#caveats