preface

Not long after learning React, I felt that actual practice was the best way to test my learning level and deepen my understanding of React, so I made this small project to share with you.

Technology stack

  • react
  • react-router
  • react-redux
  • less

preview

Basic project construction

  • Node development environment
  • Installation dependency: YARN
  • Start: YARN start
  • When it comes to third-party API interfaces, you can apply for an AppKey by yourself at the interface address. After all, the number of requests is limited

Page structure

| | - react - kitchen project name - node_modules rely on package | - public | - SRC | | - components - API request data interface components directory | | - CardList card list components - the bottom of the Footer component | - | Header head components - NavLeft left navigation | - NavRight right tags | - | | - pages page config menu configuration - Collections collection page | - details on the Detail page. | | - Home front page - the Search Search page countless according to page | | - NoMatch -... Other navigation page | - redux redux data management action - types actions reducers store | - utils tools admin. Js page App. The outer structure js page routing common. Less page style Antd theme Settings Packjon. json Global configuration readme. md README fileCopy the code

Function implementation

The routing configuration

Project as a single page, the first step, of course, is to build the page route, because it is a menu item, routing or more, so here I put all the structure of the routing config file, under NavLeft navigation components to render the menu with the map function, avoids yourself to write one duplicate code, It is also convenient to add new navigation later.

Implementation code:

import React from 'react';
import { Menu} from 'antd';
import { NavLink } from 'react-router-dom'
import MenuConfig from '.. /.. /config/menuConfig'

const SubMenu = Menu.SubMenu;
export default class NavLeft extends React.Component {

  componentWillMount() { const menuTreeNode = this.renderMenu(MenuConfig); This.setstate ({menuTreeNode})} // // menu renderMenu = (data) => {return data.map((item) => {
      if (item.children) {
        return (
          <SubMenu title={item.title} key={item.key}>
            {this.renderMenu(item.children)}
          </SubMenu>
        )
      }
      return <Menu.Item title={item.title} key={item.key}>
        <NavLink to={item.key}>{item.title}</NavLink>
      </Menu.Item>
    })
  }
  render() {
    return (
      <div>
        <Menu
          onClick={this.handleClick}
        >
          {this.state.menuTreeNode}
        </Menu>
      </div>
    )
  }
}

Copy the code

CardList component encapsulation

The recipe preview uses ANTD’s Card component. When the page starts loading, it requests many sets of data from the API, and almost every navigation page uses the same list, so the whole list should be extracted and reused as a component.

Get the list of data from the interface first

getMenuAPIList = (keyword) => {
    const num = 12
    Axios
      .jsonp({
        url: `http://api.jisuapi.com/recipe/search?keyword=${keyword}&num=${num}&appkey=9d1f6ec2fd2463f7`
      })
      .then(res => {
        if (res.status === '0') {
          let cardList = this.renderCardList(res.result.list)
          this.setState({
            cardList: cardList
          })
        }
      })
  }
Copy the code

Call the data render list page. Note here that after rendering the preview image, click to enter the details page. How to get the current data to render the details page? Three ideas come to mind:

  1. Passes the data to the common parent component, which passes the data to the detail page component via props
  2. Through the way of routing, react to the router in v4 can link to pass parameters by means of the state to the next component, a component can through this. Props. The location. The state to get the data
  3. Use Redux to manage data

I’m going to do it the second way

RenderCardList = (data) => {return data.map((item) => {
      return (
        <NavLink key={item.id} to={{
          pathname: `/common/detail/${item.id}`,
          state: item
        }} >
          <Card
            hoverable
            className="card"
            cover={<img alt="example" src={item.pic} />}
            onClick={this.openMenuDetail}
            id={item.id}
          >
            <Meta
              style={{ whiteSpace: 'nowrap' }}
              title={item.name}
              description={item.tag}
            />
          </Card>
        </NavLink>
      )
    })
  }
Copy the code

The search function

As mentioned above, link can be used to carry parameters for communication between components. For the search function here, REdux is used for data transmission between components, that is, the value of the input box is passed to the search page component, so that it can request data to THE API after it gets the value.

  1. CreateStore is used to generate a store container that takes a pure function reducer as an argument to return a new store

const store = createStore(reducer)

  1. Reducer accepts the Action and the current State as parameters and returns a new State
export function reducer(state = 1, action) {
switch (action.type) {
  case TRANSMIT:
    return action.data
  default:
    return state
  }
}
Copy the code
  1. There are an infinite number of values in the input field, that is, there are an infinite number of Actions sent by the user. You can use an Action Creator function to generate Actions
export const transmit = (data) => {
  return { type: TRANSMIT, data: data }
}
Copy the code
  1. Here we introduce react-redux to wrap the root component with the Provider. All child components get state by default
ReactDOM.render(<Provider store={store} ><App /></Provider>, document.getElementById('root'));
Copy the code
  1. Connect the UI components Header and Search with connect(). The connect method takes two parameters: mapStateToProps and mapDispatchToProps. MapStateToProps subscribes to store, and state updates are performed automatically. The Search component can get the current state of this.props. Keyword, and mapDispatchToProps as an object. Each key inside is treated as an Action Creator
export default connect(
  state => ({keyword: state}),
  {transmit}
)(Header)

export default connect(
  state => ({keyword : state}),
  {}
)(Search)
Copy the code

Since I don’t know much about Redux, the process here is a bit complicated. Simply share my understanding. You can go to see Teacher Ruan Yifeng’s Redux tutorial, which is very detailed

Collection function

Favorites function is mainly used to achieve localStorage, the main idea is: When clicking “Favorites”, check whether the data exists in localStorage. If it does not, convert the data into a string and save it in localStorage. Localstorage.setitem (), if localstorage.removeItem() exists, unbookmark it

handleCollect = () => {
    let starColor = this.state.starColor
    let isCollect = this.state.isCollect
    const menu = JSON.stringify(this.state.menu)
    const menuName = this.state.menu.name
    if (isCollect === false) {
      starColor = '#FDDA04'isCollect = ! isCollectlocalStorage.setItem(menuName, menu)
    } else {
      starColor = '#52c41a'isCollect = ! isCollectlocalStorage.removeItem(menuName)
    }
    this.setState({
      starColor,
      isCollect
    })

    message.success((isCollect ? 'Collected successfully' : 'Uncollect'), 1)}Copy the code

Project on pit

antd Input.Search

Click Search to redirect the route because ANTD encapsulates the input field and button. If you wrap Search with link, the route will jump directly without input text

Solution: Don’t use input. Search, directly use Input Input box +Button Button, get Input value in Button click event, and then use Link to wrap Button for route jump. This is the way I think of, if there is a better solution, also welcome friends to propose ~

Search page re-rendering

Act-redux: componentWillMount: componentWillMount: componentWillMount: componentWillMount: componentWillMount: function.keyword Searches for rendering the page after using the hook function is componentWillReceiveProps, this time parameters passed is nextProps keyword, rather than this. Props. The keyword

React Renders HTML code for example<br />Cannot display correctly

React JSX anti-injection attack XSS renders all HTML code in braces as strings instead of HTML code

Solution: Use the tag attribute dangerouslySetInnerHTML

<div dangerouslySetInnerHTML={{__html: code}}></div>
Copy the code

conclusion

Item portal

When I was writing a project, I encountered many small problems, which were solved one by one by slowly checking the documents. Continuous thinking and solving problems is also a part of growth.

Of course, the project still needs to be improved in many areas, if there are mistakes or deficiencies, I also hope you can give me some advice

Last but not least, shamelessly beg for a STAR😋