Как обновить выбранные элементы компонента при изменении элементов в другом компоненте?

#reactjs

Вопрос:

У меня есть экран, который выглядит так: Экран

Компонент Home выглядит примерно так, как показано ниже (просто для иллюстрации):

 function Home()
{
  return (
    <GridContainer> 
          <Grid> <LeftPanel> </Grid> 
          <Grid><RightPanel></Grid>
    </GridContainer>
  );
}
 

Мой компонент левой панели выглядит примерно так, как показано ниже (просто для иллюстрации):

 function LeftPanel()
{
  const [items, setItems] = useState([]);

  const getItemList = async() {
    setItems(  callRestMethod(url)  );
  }  

  useEffect(() => {
    (async () => {
      await getItemList();
    })();    
  });
  
  return (
    <Select> 
          {items.map( (item) => <MenuItem key={item} value={item}> item </MenuItem>)}
    </Select>
  );
}

 

Как обновить элементы списка выбора в компоненте левой панели при добавлении или удалении элемента из компонента правой панели?

Комментарии:

1. Где находятся значения состояния/выбора в правой панели? Возможно, вам потребуется применить состояние подъема Вверх , чтобы переместить параметры выбора в компонент общего предка и передать значения и обратные вызовы вниз в качестве реквизитов для обоих. Если существует много промежуточных компонентов, используйте API контекста React . В вашем случае, похоже, можно было бы переместить выбранные параметры Home .

2. @Дрю, правая панель на самом деле на 2 уровня ниже, и поэтому я не стремлюсь поднимать состояние вверх.

3. Конечно, именно поэтому я упомянул об использовании контекстного API, чтобы избежать проблемы «сверления реквизита» через промежуточные компоненты. Redux упоминается в ответе ниже, и это также сработало бы, хотя я бы не обязательно рекомендовал переход к Redux только для этого конкретного случая использования, если вы также не планируете использовать более централизованное управление состоянием. В этом случае я бы рекомендовал продолжить и использовать Redux. Смотрите redux-инструментарий для невероятно простой настройки/настройки/интеграции в ваш проект.

Ответ №1:

Я использовал react-redux и thunk

вот пример react-redux, а ниже приведен полный код

 import "./styles.css";
import React, { useEffect, useState } from "react";
import { createStore, applyMiddleware, compose } from "redux";
import { Provider, useDispatch, useSelector } from "react-redux";
import thunk from "redux-thunk";
import axios from "axios";

//REMOVE "Ahmad Rahmani" IF YOU DONT HAVE INITIAL DATA.
const initialState = {
  data: ["Ahmad Rahmani"]
};
//REDUCERS
export const MyReducer = (state = initialState, action) => {
  switch (action.type) {
    case "FETCH_ALL":
      //REMOVE initialState.data IF YOU DONT HAVE INITIAL DATA.
      return { ...state, data: [initialState.data, ...action.payload.data] };

    case "ADD":
      return { ...state, data: [...state.data, action.payload.item] };
    default:
      return state;
  }
};
//
//ACTIONS
export function addAction(item) {
  return (dispatch) => {
    //MAYBE YOU WANT TO SAVE IT IN DATABASE
    //SO YOU SHOULD CALL AN API
    //BUT NOW I DON'T
    dispatch({
      type: "ADD",
      payload: { item: item }
    });
  };
}
export function fetchAction() {
  return (dispatch) => {
    axios.get("https://jsonplaceholder.typicode.com/users").then((response) => {
      dispatch({
        type: "FETCH_ALL",
        payload: { data: response.data.map((m) => m.name) }
      });
    });
  };
}
//

export default function App() {
  const enhancers = [applyMiddleware(thunk)];
  const store = createStore(MyReducer, compose(...enhancers));
  return (
    <Provider store={store}>
      <div className="App">
        <LeftPanel />
        <RightPanel />
      </div>
    </Provider>
  );
}
export const LeftPanel = () => {
  const { data } = useSelector((state) => state);
  const dispatch = useDispatch();
  useEffect(() => {
    dispatch(fetchAction());
  }, []);
  return (
    <div className="left-panel">
      <select>
        {data.map((item) => (
          <option value={item}>{item}</option>
        ))}
      </select>
    </div>
  );
};
export const RightPanel = () => {
  const dispatch = useDispatch();
  const [text, setText] = useState("");
  const { data } = useSelector((state) => state);
  useEffect(() => {
    dispatch(fetchAction());
  }, []);
  const handleClick = (event) => {
    event.preventDefault();
    if (text === "") return;
    dispatch(addAction(text));
    setText("");
  };
  const handleChange = (event) => {
    setText(event.target.value);
  };
  return (
    <div className="right-panel">
      <input type="text" value={text} onChange={handleChange} />
      <button onClick={handleClick}>add Item</button>
      <select>
        {data.map((item) => (
          <option value={item}>{item}</option>
        ))}
      </select>
    </div>
  );
};
 

Комментарии:

1. Спасибо. Поэтому в моем случае начальное состояние должно быть получено из вызова rest. Нормально ли совершать вызовы rest, чтобы получить начальное состояние для значения состояния redux?

2. Пожалуйста, да, вы можете позвонить в api для получения исходных данных, я обновил ответ и сделал то, что вы упомянули.