Изменение состояния компонентов с помощью функции в другом файле

#reactjs #react-router

#reactjs #react-маршрутизатор

Вопрос:

Я совсем новичок в React и не совсем понимаю, как заставить это работать. Я пытаюсь обновить App.js состояние пользователя с информацией, поступающей из MediaAPI.js . Я попытался создать метод в компоненте приложения, а затем вызвать метод из MediaAPI.js с данными JSON в скобках, но на самом деле это не работает. Любая помощь будет высоко оценена!

App.js

 class App extends Component {
  state = {
    user: [],
  };


  updateUser = (data) => {
    this.setState({user: data});
  };


  render() {
    return (
        <Router>
            <Nav/>
              <Route exact path="/" component={Login}/>
              <Route exact path="/home" render={(props) => (
                  <Home {...props} picArray={this.state.picArray}/>
              )}/>
              <Route exact path="/profile" component={Profile}/>
              <Route exact path="/single/:id" component={Single}/>
        </Router>
    );
  }
}


export default App;
  

MediaAPI.js

 import App from '../App';

  const login = (username, password) => {
  return fetch(loginUrl, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({username, password})
  }).then(response => response.json()).then(json=> {
    console.log(json);
    App.updateUser(json);
  });
};
  

Ответ №1:

Этот способ App.updateUser(json); работает только тогда, когда ваш метод статичен, а в статическом методе у вас нет доступа к this , есть способы добиться этого:

1:

вы можете использовать свою функцию входа в свой компонент приложения следующим образом :

 class App extends Component {
  state = {
    user: [],
  };

  login = (username, password) => {
    return fetch(loginUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({username, password})
    }).then(response => response.json()).then(data=> {
       this.setState({user: data});
    });
  };


  componentDidMount(data){
    this.login('username', 'password');
  };


  render() {
    return (
        <Router>
            <Nav/>
              <Route exact path="/" component={Login}/>
              <Route exact path="/home" render={(props) => (
                  <Home {...props} picArray={this.state.picArray}/>
              )}/>
              <Route exact path="/profile" component={Profile}/>
              <Route exact path="/single/:id" component={Single}/>
        </Router>
    );
  }
}


export default App;
  

примечание:

а также вы можете упростить метод входа в систему, используя Async / await, подобный этому :

   login = async (username, password) => {
    const response =  await fetch(loginUrl,
         { method: 'POST', headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({username, password})
    });
    const user =  await response.json();
    this.setState({ user });
  };
  

примечание:

а также вы можете сделать вот так:

 import { login } from 'MediaAPI.js';

class App extends Component {
  state = {
    user: [],
  };

  async componentDidMount(data){
    const user = await login('username', 'password');
    this.setState({ user });
  };


  render() {
    return (
        <Router>
            <Nav/>
              <Route exact path="/" component={Login}/>
              <Route exact path="/home" render={(props) => (
                  <Home {...props} picArray={this.state.picArray}/>
              )}/>
              <Route exact path="/profile" component={Profile}/>
              <Route exact path="/single/:id" component={Single}/>
        </Router>
    );
  }
}


export default App;
  

MediaAPI.js

    export const login = (username, password) => {
      return fetch(loginUrl, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({username, password})
      }).then(response => response.json());
    };
  

2:

вы можете создать компонент и в этом компоненте использовать App и задать ему ссылку, а затем использовать updateUser метод.

—- есть другие способы, но я думаю, что эти два являются лучшими.

Ответ №2:

Насколько я знаю, я бы сказал, что ваш подход является антишаблоном. Ниже я бы подошел к этому.

 
import mediaAPI from 'MediaAPI'

class App extends Component {
  state = {
    user: [],
  };

  // this is a React lifecycle hook that will be
  // called when the component has mounted.
  componentDidMount() {
    mediaAPI()
      .then(res => res.json())
      .then(this.setUserData)
  }


  setUserData = (data) => {
    this.setState({user: data});
  };


  render() {
    return (
        <Router>
            <Nav/>
              <Route exact path="/" component={Login}/>
              <Route exact path="/home" render={(props) => (
                  <Home {...props} picArray={this.state.picArray}/>
              )}/>
              <Route exact path="/profile" component={Profile}/>
              <Route exact path="/single/:id" component={Single}/>
        </Router>
    );
  }
}