如何在React Hooks中更改提供者的价值

时间:2019-10-02 13:07:40

标签: javascript reactjs react-hooks

我目前有使用Context和Memo Hooks API的练习代码

codesandbox

这是一个代码段

export const InputContext = createContext()

export const ParentProvider = ({ initialValues, children }) => {
    console.log(initialValues)
    const [values, setValues ] = useState(initialValues);
    const value = {
        values,
        setValues
    }
    return <InputContext.Provider value={value}>{children}</InputContext.Provider>
}

我想要的是在单击“编辑”后使用Context API更新包含指标的数组的值。

问题是通过备忘录访问后我无法访问上下文

2 个答案:

答案 0 :(得分:1)

使用useContext,您需要传递整个context对象(不仅是Consumer)。像这样使用它

const Component = () =>{
    const context = useContext(InputContext)
    const { values, setValues } = context

    const handleChange = () => setValues('foo')        

    return(
        <>
            {values}
            <button onClick={handleChange}>Change</button>
        </>
    )
}

答案 1 :(得分:1)

您需要使用提供程序包装所有需要访问上下文的组件。像这样...

Edit naughty-thunder-msxz1


ParentProvider.js

import React, { createContext, useState } from "react";

const INITIAL_STATE = [];
export const InputContext = createContext(INITIAL_STATE);

export const ParentProvider = ({ children }) => {
  const [values, setValues] = useState(INITIAL_STATE);

  React.useEffect(() => {
    console.log("[parentprovider.js]::new values", values);
  }, [values]);

  return (
    <InputContext.Provider value={{ values, setValues }}>
      {children}
    </InputContext.Provider>
  );
};

ShowIndicator.js

import React, { memo, useContext, useState } from "react";
import { Button } from "react-bootstrap";
import { InputContext } from "./ParentProvider";

const ShowIndicator = memo(
  ({ name, context }) => {
    const [_name, _setName] = useState(name);
    const [text, setText] = useState();
    const { values, setValues } = useContext(InputContext);

    const editData = e => {
      let newValues = [...values];
      newValues[values.indexOf(_name)] = text;
      setValues(newValues);
      _setName(text);
    };

    const handleTextChange = e => setText(e.target.value);

    const renderDatas = () => {
      return (
        <div key={_name} className="d-flex justify-content-between">
          <input
            className="d-flex align-items-center"
            defaultValue={_name}
            onChange={handleTextChange}
          />
          <div>
            <Button
              variant="info"
              style={{ marginRight: "10px" }}
              onClick={editData}
            >
              Edit
            </Button>
            <Button variant="dark">Delete</Button>
          </div>
        </div>
      );
    };

    return <div style={{ marginBottom: "5px" }}>{renderDatas()}</div>;
  },
  (prev, next) => prev.value === next.value
);

export default ShowIndicator;

App.js

import React, { useState, useContext } from "react";
import "./styles.css";
import { Form, Button, Container } from "react-bootstrap";
import ShowIndicator from "./ShowIndicator";
import { InputContext } from "./ParentProvider";

function App() {
  const [curText, setCurText] = useState("");
  const { values, setValues } = useContext(InputContext);

  const onSubmit = e => {
    e.preventDefault();
    if (!values.includes(curText)) {
      values ? setValues([...values, curText]) : setValues([curText]);
      setCurText("");
    }
  };

  const onChange = e => setCurText(e.target.value);

  return (
    <div>
      <Container style={{ marginTop: "10px", textAlign: "center" }}>
        <div>Add Indicator</div>
        <Form inline onSubmit={onSubmit} style={{ marginBottom: "1rem" }}>
          <Form.Control
            style={{ flex: "1 0 0" }}
            onChange={onChange}
            value={curText}
          />
          <Button type="submit" variant="success">
            Submit
          </Button>
        </Form>
        {values &&
          values.map((data, index) => {
            return <ShowIndicator key={index} name={data} />;
          })}
      </Container>
    </div>
  );
}

export default App;

index.js

import React from "react";
import App from "./App";
import { render } from "react-dom";
import { ParentProvider } from "./ParentProvider";

render(
  <ParentProvider>
    <App />
  </ParentProvider>,
  document.getElementById("root")
);