Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a function with React Context API to child component nested deep in the tree

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;
like image 819
acd37 Avatar asked Aug 24 '18 15:08

acd37


People also ask

How do you pass property from parent to child in React?

To pass data from a child component to its parent, we can call a parent function from the child component with arguments. The parent function can be passed down to the child as a prop, and the function arguments are the data that the parent will receive.

Can we pass data from child to parent in React using context?

The main idea of using context is to allow components to access some global data and re-render when the global data changes. Context solves the prop drilling problem: when you have to pass props from parent to a lot of child components. 👉 On the other hand, integrating context adds complexity.


1 Answers

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.

like image 104
devserkan Avatar answered Sep 18 '22 14:09

devserkan