Как обновить одно и то же избыточное состояние одновременно на двух разных компонентах? - PullRequest
1 голос
/ 03 апреля 2020

У меня есть сценарий React Native, в котором у меня есть два компонента, один из которых textInput, а другой - SVG чертеж. Заполнив textInput и нажав кнопку, текст вставляется в качестве экземпляра данных в массив, сохраненный в состоянии избыточности, с помощью действия dispatch (назовем его textListState).

//TEXT INPUT COMPONENT
//this code is just for presentation. it will cause errors obviously
const dispatch = useDispatch();
const submitHandler = (enteredText) => {
    dispatch(submitData(enteredText))
};

return(
    <TextInput ...... />
    <TouchableOpacity onPress={() => submitHandler(enteredText) } />
)

Теперь компонент SVG обновляет цвет заливки всех объектов, сохраненный в textListState, с помощью функции (например, setFillColor). Это делается внутри useEffect ловушки с зависимостью, установленной в проп (например, propA).

Теперь проблема в том, что мне нужно добавить textListState в качестве зависимости к useEffect, потому что я хочу, чтобы вновь введенный текст из textInput был включен в компонент SVG. Но тем самым я создаю бесконечное l oop, потому что setFillColor также обновляет textListState.

//SVG COMPONENT
const [textList, setTextList] = useState([]);
const textListState = useSelector(state => state.textListState);

const dispatch = useDispatch();
const setFillColor= useCallback((id, fill) => {
    dispatch(updateFillColor(id, fill))
}, [dispatch]);

useEffect(() => {
    //INFINITE LOOP BECAUSE textListState  KEEPS UPDATING WITH setFillColor
    const curTextList = [];

    for (const [i, v] of textListState.entries()) {
        setFillColor(5, "white")

        curTextList.push(
            <someSVGComponent />
        )
    }
    setTextList(curTextList);
}, [props.propA, textListState])

return(
    <G>
        {textList.map(x => x)}
    </G>
)

Как мне добиться того, чтобы иметь возможность добавлять вновь вставленный текст в SVG компонент без создания бесконечного l oop?


РЕДАКТИРОВАТЬ:

Редукционное действие

export const UPDATE_TEXT = "UPDATE_TEXT";
export const SUBMIT_DATA = "SUBMIT_DATA";

export const updateFillColor = (id, fill) => {
    return { type: UPDATE_TEXT, id: id, fill: fill }
};

export const submitData= (text) => {
    return { type: SUBMIT_DATA, text: text }
};

Редуктор

import { TEXT } from "../../data/texts";
import { UPDATE_TEXT } from "../actions/userActions";
import { INSERT_TEXT } from "../actions/userActions";

// Initial state when app launches
const initState = {
    textListState: TEXT
};

const textReducer = (state = initState, action) => {
    switch (action.type) {
        case INSERT_TEXT :
            return {
                ...state,
                textListState: [
                    ...state.textListState,
                    action.text
                ]
            }
        case UPDATE_TEXT :
            const curText = state.textListState.filter(text => text.id === action.id)[0];

            return {
                ...state,
                textListState: [
                    ...state.textListState.slice(0, curIndex), //everything before current text
                    curText.fill = action.fill,
                    ...state.textListState.slice(curIndex + 1), //everything after current text
                ]
            }

        default:
            return state;
    }
};

export default textReducer;

1 Ответ

1 голос
/ 03 апреля 2020

, если вы хотите запускать useEffect только при добавлении нового текста, тогда используйте textListState.length вместо textListState в списке зависимостей.

Если вы хотите сделать это как при обновлении, так и при вставке (т. Е. Хотите запускать даже при обновлении текста во входных данных), используйте логический флаг textUpdated в textListState и продолжайте переключать его, когда есть обновить или вставить и использовать textListState.textUpdated в списке зависимостей.

...