Как сделать компонент контролируемого ввода в Redux? - PullRequest
2 голосов
/ 06 марта 2020

Я реализую функцию поиска mov ie, используя API moviedb. Я реализовал только в React, но я хочу сделать это в Redux. Вот мой подход в React.

Заголовок. js

import React, { Component } from "react"
import { Navbar, Form, FormControl } from "react-bootstrap"
import { NavLink } from "react-router-dom"
import axios from "axios"
import MovieCards from "./MovieCards"
const apiKey = process.env.REACT_APP_MOVIE_DB_API_KEY

class Header extends Component {
  state = {
    isSearching: false,
    value: "",
    movies: []
  }

  searchMovies = async val => {
    this.setState({ isSearching: true })
    const res = await axios.get(
      `https://api.themoviedb.org/3/search/movie?api_key=${apiKey}&language=en-US&query=${val}&page=1&include_adult=true`
    )
    const movies = await res.data.results
    this.setState({ movies: movies, isSearching: false })
  }

  handleChange = e => {
    const { name, value } = e.target
    this.searchMovies(value)
    this.setState({
      [name]: value
    })
  }

  render() {
    return this.state.value === "" ? (
      <div>
        <Navbar
          bg="dark"
          expand="lg"
          style={{ justifyContent: "space-around" }}
        >
          <NavLink to="/">
            <Navbar.Brand>Movie Catalogue</Navbar.Brand>
          </NavLink>
          <Navbar.Toggle aria-controls="basic-navbar-nav" />
          <Navbar.Collapse id="basic-navbar-nav">
            <Form inline>
              <FormControl
                type="text"
                placeholder="Search"
                className="mr-sm-2"
                onChange={this.handleChange}
                name="value"
                value={this.state.value}
              />
            </Form>
          </Navbar.Collapse>

          <NavLink to="/popular">Popular</NavLink>
          <NavLink to="/now-playing">Now Playing</NavLink>
          <NavLink to="/top-rated">Top Rated</NavLink>
          <NavLink to="/upcoming">Upcoming</NavLink>
        </Navbar>

        {this.state.movies.map((movie, i) => {
          return <MovieCards key={i} movie={movie} />
        })}
      </div>
    ) : (
      <div>
        <Navbar
          bg="dark"
          expand="lg"
          style={{ justifyContent: "space-around" }}
        >
          <NavLink to="/">
            <Navbar.Brand>Movie Catalogue</Navbar.Brand>
          </NavLink>
          <Navbar.Toggle aria-controls="basic-navbar-nav" />
          <Navbar.Collapse id="basic-navbar-nav">
            <Form inline>
              <FormControl
                type="text"
                placeholder="Search"
                className="mr-sm-2"
                onChange={this.handleChange}
                name="value"
                value={this.state.value}
              />
            </Form>
          </Navbar.Collapse>

          <p style={{ color: "white" }}>
            Search results for " {this.state.value} "
          </p>
        </Navbar>

        {this.state.movies.map((movie, i) => {
          return <MovieCards key={i} movie={movie} />
        })}
      </div>
    )
  }
}

export default Header

Я хочу сделать это с помощью Redux, поэтому я делаю это таким образом.

Заголовок. js

import React, { Component } from "react"
import { Navbar, Form, FormControl } from "react-bootstrap"
import { NavLink } from "react-router-dom"
import axios from "axios"
import { connect } from "react-redux"
import { movieSearch } from "../actions/index"
import MovieCards from "./MovieCards"
const apiKey = process.env.REACT_APP_MOVIE_DB_API_KEY

class Header extends Component {

  handleChange = e => {
    const { name, value } = e.target
    this.props.dispatch(movieSearch(value)) // I'm not sure if this is the right approach. I'm dispatching and then setting state.
    this.setState({
      [name]: value
    })
  }

  render() {
    return this.state.value === "" ? (
      <div>
        <Navbar
          bg="dark"
          expand="lg"
          style={{ justifyContent: "space-around" }}
        >
          <NavLink to="/">
            <Navbar.Brand>Movie Catalogue</Navbar.Brand>
          </NavLink>
          <Navbar.Toggle aria-controls="basic-navbar-nav" />
          <Navbar.Collapse id="basic-navbar-nav">
            <Form inline>
              <FormControl
                type="text"
                placeholder="Search"
                className="mr-sm-2"
                onChange={this.handleChange} 
                name="value" 
                value={this.state.value} 
              />
            </Form>
          </Navbar.Collapse>

          <NavLink to="/popular">Popular</NavLink>
          <NavLink to="/now-playing">Now Playing</NavLink>
          <NavLink to="/top-rated">Top Rated</NavLink>
          <NavLink to="/upcoming">Upcoming</NavLink>
        </Navbar>

        {this.state.movies.map((movie, i) => {
          return <MovieCards key={i} movie={movie} />
        })}
      </div>
    ) : (
      <div>
        <Navbar
          bg="dark"
          expand="lg"
          style={{ justifyContent: "space-around" }}
        >
          <NavLink to="/">
            <Navbar.Brand>Movie Catalogue</Navbar.Brand>
          </NavLink>
          <Navbar.Toggle aria-controls="basic-navbar-nav" />
          <Navbar.Collapse id="basic-navbar-nav">
            <Form inline>
              <FormControl
                type="text"
                placeholder="Search"
                className="mr-sm-2"
                onChange={this.handleChange}
                name="value"
                value={this.state.value}
              />
            </Form>
          </Navbar.Collapse>

          <p style={{ color: "white" }}>
            Search results for " {this.state.value} "
          </p>
        </Navbar>

        {this.state.movies.map((movie, i) => {
          return <MovieCards key={i} movie={movie} />
        })}
      </div>
    )
  }
}

const mapStateToProps = (state) => {
   return state
}

export default connect(mapStateToProps)(Header)

Действия / индекс. js

export const movieSearch = val => {
  const movieSearchUrl = `https://api.themoviedb.org/3/search/movie?api_key=${apiKey}&language=en-US&query=${val}&page=1&include_adult=true`

  return async dispatch => {
    dispatch({ type: "SEARCHING_MOVIES_START" })
    try {
      const res = await axios.get(movieSearchUrl)
      dispatch({
        type: "SEARCHING_MOVIES_SUCCESS",
        data: { searchResults: res.data.results }
      })
    } catch (err) {
      dispatch({
        type: "SEARCHING_MOVIES_FAILURE",
        data: { error: "Could not find the movie" }
      })
    }
  }
}

redurs / movieSearchReducer. js

const initialState = {
  value: "",
  isSearchingMovies: false,
  isSearchedMovies: false,
  movieList: [],
  searchingError: null
}

export const movieSearchReducer = (state = initialState, action) => {
  switch (action.type) {
    case "SEARCHING_MOVIES_START":
      return {
        ...state,
        isSearchingMovies: true,
        searchingError: null
      }
    case "SEARCHING_MOVIES_SUCCESS":
      return {
        ...state,
        isSearchingMovies: false,
        isSearchedMovies: true,
        movieList: action.data,
        searchingError: null
      }
    case "SEARCHING_MOVIES_FAILURE":
      return {
        ...state,
        searchingError: action.data.error
      }
  }
}

Я не уверен, как реализовать часть представленной ниже части формы ввода в Redux. Пожалуйста, помогите, если можете.

    onChange={this.handleChange}
    name="value"
    value={this.state.value}

Ответы [ 2 ]

1 голос
/ 06 марта 2020

Когда вы переходите из состояния в компоненте в режим редукции, вы обычно удаляете состояние реакции и извлекаете состояние избыточности из «реквизита».

Таким образом, шаг 1 состоит в том, чтобы полностью избавиться от вашего setState.

value = {this.state.value}

станет

value = {this.props.movieList}

Чтобы получить список фильмов в реквизите вам нужно обернуть ваш компонент в «контейнер» и использовать mapStateToProps для сопоставления состояния редукса с вашими реквизитами.

Подробнее см. https://react-redux.js.org/api/connect

0 голосов
/ 06 марта 2020

Если вы используете Redux для хранения фильмов, вы можете удалить локальное состояние для своего компонента и использовать вместо него видеоинспекцию redux.

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