Почему мои функции React Context Helper используют устаревшее состояние? - PullRequest
0 голосов
/ 11 апреля 2020

Спасибо, что взглянули на это ...

Вот моя проблема; в моем приложении «native native» я написал контекст React, который управляет «сообщениями заголовка», которые я могу вызвать в любом месте базы кода и прикрепить сообщение под элементом заголовка моего приложения (отображается глобально). Этот процесс работает, и я могу обработать свое первое Заголовочное сообщение, которое я добавил, используя вспомогательную функцию .addNewMessage ('id', 'JSX.Element'); но когда я звоню это снова; предыдущее сообщение удаляется, и новое сообщение отображается ...

Я полагаю, что это происходит потому, что функция .addNewMessage (), определенная в контексте, указанном ниже, ссылается на состояние ссылки ... Вызывая его, обновляется состояние .. затем снова звоню; он все еще ссылается на исходное состояние ... Посмотрите журналы консоли, чтобы увидеть, как это закончится с двумя последующими вызовами.

Код за контекстом; Вспомогательные функции объявлены в функции ...

import * as React from 'react';
import { Text } from 'react-native';

export interface IElements {
  [key: string] : JSX.Element;
}

export interface IState {
  setState : (newState: IState) => void;
  addNewMessage : (id: string, elem: JSX.Element) => void;
  removeMessage : (id: string) => void;
  returnAllMessages : () => JSX.Element[]
  messages : IElements;
}

export interface IProps {
  children : JSX.Element[] | JSX.Element;
}

const defaultValues: IState = {
  setState: () => undefined,
  addNewMessage: () => undefined,
  removeMessage: () => undefined,
  returnAllMessages: () => [],
  messages : {'test1': <Text>FooBarLoremIpsum</Text>},
};

export const HeaderMessagesContext: React.Context<IState> = React.createContext<IState>(defaultValues);

const CTX_HeaderMessages: React.FC<IProps> = (props: IProps) => {
  const [state, updateState] = React.useState(defaultValues);

  // Every time I call this function, it is acting like it is using
  // defaultValues instead of state... I assume this is a weird side effect
  // of defining a function then storing an instance of that function inside
  // the state object itself...? But anytime I try and declare a side effect
  // that would essentially store a new instance of the function; I find myself
  // in an infinite Loop... I'm struggling with the pattern here to make this work :/
  const addNewMessage = (id: string, elem : JSX.Element) => {
    console.log('State Coming into "AddNewMessage"', state);
    const newMessages = {...state.messages};
    newMessages[id] = elem;
    console.log('State Exiting "AddNewMessage"', {...state, messages : newMessages});
    updateState({...state, messages : newMessages});
  };
  const removeMessage = (id: string) => { if(state.messages[id]) {delete state.messages[id]} }
  const returnAllMessages = () => Object.keys(state.messages).map(key => state.messages[key]);

  const val: IState = {
    ...state,
    setState : updateState,
    addNewMessage,
    removeMessage,
    returnAllMessages
  }

  return (
    <HeaderMessagesContext.Provider value={val}>
      {props.children}
    </HeaderMessagesContext.Provider>
  );
};

export default CTX_HeaderMessages;

Chrome Журналы консоли

Эти журналы показывают, что я испытываю ... Я хотел бы обратить ваше внимание на значение объекта сообщения. Когда я вызываю функцию в первый раз; значение добавлено; когда я вызываю функцию во второй раз; Обратите внимание, что значение первого вызова (на предыдущей строке) отсутствует ...

State Comming into "AddNewMessage" 
    {messages: {…}, setState: ƒ, addNewMessage: ƒ, removeMessage: ƒ, returnAllMessages: ƒ}
    addNewMessage: ƒ addNewMessage()
    messages: {test1: {…}}
    removeMessage: ƒ removeMessage()
    returnAllMessages: ƒ returnAllMessages()
    setState: ƒ setState()
    __proto__: Object

HeaderMessages.tsx:38 State Exiting "AddNewMessage" 
    {messages: {…}, setState: ƒ, addNewMessage: ƒ, removeMessage: ƒ, returnAllMessages: ƒ}
    addNewMessage: ƒ addNewMessage()
    messages: {test1: {…}, SuggestUpdate_Line78: {…}}
    removeMessage: ƒ removeMessage()
    returnAllMessages: ƒ returnAllMessages()
    setState: ƒ setState()
    __proto__: Object

HeaderMessages.tsx:35 State Comming into "AddNewMessage" 
    {messages: {…}, setState: ƒ, addNewMessage: ƒ, removeMessage: ƒ, returnAllMessages: ƒ}
    addNewMessage: ƒ addNewMessage()
    messages: {test1: {…}}
    removeMessage: ƒ removeMessage()
    returnAllMessages: ƒ returnAllMessages()
    setState: ƒ setState()
    __proto__: Object

HeaderMessages.tsx:38 State Exiting "AddNewMessage" 
    {messages: {…}, setState: ƒ, addNewMessage: ƒ, removeMessage: ƒ, returnAllMessages: ƒ}
    addNewMessage: ƒ addNewMessage()
    messages: {test1: {…}, SuggestUpdate_Line79: {…}}
    removeMessage: ƒ removeMessage()
    returnAllMessages: ƒ returnAllMessages()
    setState: ƒ setState()
    __proto__: Object

1 Ответ

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

Передача setState в вашем контексте является избыточной, я думаю. и вам просто нужно хранить сообщения в вашем состоянии, а не методы CRUD. взгляните на приведенный ниже код, я думаю, что он будет работать.

import * as React from 'react';
import { Text } from 'react-native';

export interface IElements {
  [key: string] : JSX.Element;
}

export interface IState {
  addNewMessage : (id: string, elem: JSX.Element) => void;
  removeMessage : (id: string) => void;
  returnAllMessages : () => JSX.Element[]
  messages : IElements;
}

export interface IProps {
  children : JSX.Element[] | JSX.Element;
}

const defaultValues: IState = {
  addNewMessage: () => undefined,
  removeMessage: () => undefined,
  returnAllMessages: () => [],
  messages: { test1: <Text>FooBarLoremIpsum</Text> },
};

const defaultMessages : IElements = {
  messages: { test1: <Text>FooBarLoremIpsum</Text> },
};

export const HeaderMessagesContext: React.Context<IState> = React.createContext<IState>(defaultValues);

const CTX_HeaderMessages: React.FC<IProps> = (props: IProps) => {
  const [state, updateState] = React.useState<IElements>(defaultMessages);

  // Every time I call this function, it is acting like it is using
  // defaultValues instead of state... I assume this is a weird side effect
  // of defining a function then storing an instance of that function inside
  // the state object itself...? But anytime I try and declare a side effect
  // that would essentially store a new instance of the function; I find myself
  // in an infinite Loop... I'm struggling with the pattern here to make this work :/
  const addNewMessage = (id: string, elem : JSX.Element) => {
    console.log('State Coming into "AddNewMessage"', state);
    const newMessages = { ...state };
    newMessages[id] = elem;
    console.log('State Exiting "AddNewMessage"', newMessages);
    updateState(newMessages);
  };
  const removeMessage = (id: string) => { if (state[id]) { delete state[id]; } };
  const returnAllMessages = () => Object.keys(state).map((key) => state[key]);

  const val: IState = {
    messages: state,
    addNewMessage,
    removeMessage,
    returnAllMessages,
  };

  return (
    <HeaderMessagesContext.Provider value={val}>
      {props.children}
    </HeaderMessagesContext.Provider>
  );
};

export default CTX_HeaderMessages;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...