Как сохранить значение состояния в React после вызова другой страницы

#reactjs #parameter-passing #state

#reactjs #передача параметров #состояние

Вопрос:

У меня есть простое приложение для загрузки React / Spring, в котором я хотел бы передать строку поиска на страницу сведений, а затем вернуться к родительской, используя ту же строку поиска в качестве параметра.

В этот момент родительская страница должна принять значение и сохранить его обратно в состоянии.

Что касается существующего кода, когда родительский файл открывается, он устанавливает набор значений в состоянии, включая строку поиска:

 constructor(props) {
    super(props);
    const {cookies} = props;
    this.state = {
      word: '',
      newWord: '',
      searchString: '',
      licenses: [],
      licensePage: [],
      csrfToken: cookies.get('XSRF-TOKEN'), 
      isLoading: true,
      licensesPerPage: 7,
      activePage: 1,
      begin: 0,
      end: 7
    };
  

Страница сведений (страница редактирования) вызывается нажатием кнопки на родительской странице:

 <Button size="sm" color="primary" tag={Link} to={"/licenses/"   license.id}>Edit</Button>
  

Страница сведений возвращается к родительской, нажав кнопку «Сохранить» или «Отмена»:

 <div>
    <Button color="primary" type="submit">Save</Button>{' '}
    <Button color="secondary" tag={Link} to="/licenses">Cancel</Button>
</div>
  

Отправка обрабатывается функцией «onSubmit», которая вызывает «handleSubmit:

 <Form onSubmit={this.handleSubmit}>
  

Это handleSubmit — здесь уместна только последняя строка:

 async handleSubmit(event) {

    event.preventDefault();

    if(this.handleValidation()){
    } else {
      return;
    }

    const {item, csrfToken} = this.state;

    await fetch('/api/license'   (item.id ? '/'   item.id : '') , {
      method: (item.id) ? 'PUT' : 'POST',
      headers: {
        'X-XSRF-TOKEN': csrfToken,
        'Accept': 'application/json',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(item),
      credentials: 'include'
    });
    this.props.history.push('/licenses');
  }
  

Это последняя строка, которую мне нужно изменить:

 this.props.history.push('/licenses');
  

должно быть:

 this.props.history.push('/license/search/{searchString}');
  

Мне просто нужно заполнить строку поиска. Затем я мог бы применить ту же логику к отмене.

Итак, мой вопрос в том, как передать строку поиска дочернему элементу, а затем захватить ее, когда она передается родительскому элементу в URL?

======================= Попытка реализовать сбой ответа на ошибку «не работает» ==========

Я попробовал ответ, но не смог преобразовать его в подход, основанный на классах (я использую классы, а не функции).

Вот код. Обратите внимание, что я временно добавил «2» к именам переменных, чтобы их не путали с существующим кодом.

App.js

 import React, { Component } from 'react';
import './App.css';
import Home from './Home';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import LicenseList from './LicenseList';
import LicenseEdit from './LicenseEdit';
import ImportList from './ImportList';
import { CookiesProvider } from 'react-cookie';

class App extends Component {

 state = {
    searchString2: ""
  };

  updateSearchString2 = (searchString2) => {
    this.setState({
      searchString2
    });
  };

  render() {
    return (
      <CookiesProvider>
        <Router>
          <Switch>
            <Route path='/' exact={true} component={Home}/>
            <Route path='/licenses' exact={true} component={LicenseList}
                searchString2={this.state.searchString2} // props passed will be same value passed to DetailsPage
                updateSearchString2={this.updateSearchString2}
            />
            <Route path='/imports' exact={true} component={ImportList}/>
            <Route path='/licenses/:id' component={LicenseEdit}/>
          </Switch>
        </Router>
      </CookiesProvider>
    )
  }
}

export default App;
  

Соответствующий код в лицензии list.js

   <div>
    <input type="text" value={this.props.searchString2} onChange={(e) =>  this.props.updateSearchString2(e.target.value)} />
  

Это выдает ошибку

 TypeError: _this6.props.updateSearchString2 is not a function
  

Есть мысли?

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

1. В вашем вопросе вы спросили «как передать searchString дочернему элементу, а затем захватить его, когда он будет передан родительскому элементу». Можете ли вы подтвердить, является ли компонент страницы сведений дочерним по отношению к упомянутому вами компоненту родительской страницы? Можете ли вы также опубликовать свои маршруты?

2. Я не уверен, что это дочерний элемент, так как это мое первое приложение React, и я, честно говоря, просто пробиваюсь через это. Я добавил код в вопрос. Обратите внимание, что моя стратегия изменилась с использования исходного идентификатора «/ licenses» в маршруте на «/license/{searchString}». Идея заключается в том, что если searchString имеет значение null, API вернет все лицензии (как это делает оригинал «/licenses»), но если строка содержит что-то, она вернет только соответствующие лицензии.

Ответ №1:

У вас может быть 1 источник достоверности для searchString состояния, так что это состояние будет передано как prop как компоненту «ParentPage», так и компоненту «DetailsPage». Для этого у вас может быть общий родительский компонент как для ParentPage, так и для компонента DetailsPage

 export default class App extends React.Component {
  state = {
    searchString: ""
  };

  updateSearchString = (searchString) => {
    this.setState({
      searchString
    });
  };

  render() {
    return (
      <div className="App">
        <Route
          exact
          path="/"
          render={() => (
            <ParentPage
              searchString={this.state.searchString} // props passed will be same value passed to DetailsPage
              updateSearchString={this.updateSearchString}
            />
          )}
        />
        <Route
          path="/license"
          render={() => <DetailsPage searchString={this.state.searchString} />}
        />
      </div>
    );
  }
}
  

В этом сценарии, независимо от какой-либо маршрутизации, которая произошла, или каких-либо изменений состояния, searchString значение останется неизменным во всех ваших компонентах

Редактировать frosty-wave-zkiiy

Для этого требования:

Идея заключается в том, что если searchString имеет значение null, API вернет все лицензии (как это делает «/licenses»), но если строка содержит что-то, она вернет только соответствующие лицензии.

поскольку у вас уже есть доступ к searchString , на этом этапе вы можете использовать операторы условий на основе searchString значения и оценить, нужен ли вам API для возврата всех лицензий или нет и т. Д

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

1. У меня возникли проблемы с преобразованием этого в реализацию на основе классов — я получаю «updateSearchString», это не функция. Если вы хотите взглянуть, я опубликовал код в теле.

2. вы можете использовать render prop вместо component prop для вашего <Route/> . внутри render функции обратного вызова вы помещаете свой JSX вместе с реквизитами. Пример: render={() => ( <LicenseList searchString2={this.state.searchString2} updateSearchString2={this.updateSearchString2} /> )}

3. Спасибо — это работает! Итак, просто изменив «Component» на «render», это позволяет передавать функцию? Учитывая это, есть ли какая-либо причина когда-либо использовать Component в команде route? Может быть, потому, что это легче читать… Мне действительно нужно собрать все воедино и понять различия между программированием на основе классов и функциональным программированием в React. С фоном в Java, очевидно, классы проще и интуитивно понятнее, но функциональное программирование похоже на то, что такое React, по крайней мере, на основе примеров, которые я вижу.

4. Технически component можно использовать таким же образом. Основное отличие заключается в том, что, как объясняется в документации , использование component создаст новые элементы React для рендеринга, это означает, что старый размонтируется и отображается совершенно новый элемент React. Продолжайте и протестируйте его в моем CodeSandbox. Просто замените render prop на component prop. Вы заметите, что ввод в поле ввода (т. Е. Обновление состояния) приведет к монтированию нового элемента — поэтому первоначальный ввод больше не находится в DOM, поэтому focus теряется.