«Маленький помощник повара» — бой проекта React+AntD

React.js
«Маленький помощник повара» — бой проекта React+AntD

предисловие

Изучая React в течение длительного времени, я почувствовал, что реальный бой — лучший способ проверить мой уровень обучения.Кстати, я также углубил свое понимание React, поэтому я сделал такой небольшой проект, чтобы поделиться им.

стек технологий

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

предварительный просмотр

Базовое строительство проекта

  • среда разработки узла
  • Установить зависимости: пряжа
  • Старт проекта: старт пряжи
  • Когда дело доходит до сторонних интерфейсов API, друзья могут идти сами по себе.адрес интерфейсаПодайте заявку на appkey, ведь количество запросов ограничено.

структура страницы

|-react-kitchen 项目名
    |-node_modules  依赖包
    |-public  
    |-src  
        |-api   请求数据接口 
        |-components    组件目录
            |-CardList      卡片列表组件
            |-Footer        底部组件
            |-Header        头部组件
            |-NavLeft       左侧导航
            |-NavRight      右侧标签
        |-config        菜单配置
        |-pages         页面
            |-Collections   收藏页
            |-Detail        详情页
            |-Home          首页
            |-Search        搜索页
            |-NoMatch       无数据页
            |-。。。        其他导航页
        |-redux         redux数据管理
            action-types  
            actions
            reducers
            store
        |-utils         工具类
        admin.js        页面外层结构
        App.js          页面路由
        common.less     页面样式
        index.js        入口文件
    config-overrides.js     antd主题设置
    packjon.json            全局配置
    README.md               readme文件

Реализация функции

конфигурация маршрутизации

Поскольку это одностраничный проект, первым шагом, конечно же, является построение маршрутизации страницы.Поскольку это проект-рецепт, маршрутов по-прежнему много.Здесь я помещаю структуру маршрутизации в файл конфигурации и использую функцию карты под навигацией NavLeft. Чтобы отобразить меню, он не только позволяет избежать написания повторяющегося кода один за другим, но и облегчает добавление новой навигации позже.

Код реализации:

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
    })
  }
  // // 菜单渲染
  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>
    )
  }
}

Пакет компонентов CardList

Изображение для предварительного просмотра рецепта использует компонент карты antd. Когда страница загружается впервые, она запрашивает множество наборов данных из API, и почти каждая страница навигации использует один и тот же список. Здесь весь список должен быть извлечен в компонент используются повторно.

Сначала получите список данных из интерфейса

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
          })
        }
      })
  }

Затем вызовите страницу списка рендеринга данных. Здесь следует отметить, что после рендеринга предварительного изображения нажмите, чтобы перейти на страницу сведений. Как получить текущие данные для рендеринга страницы сведений?
Мне приходят в голову три идеи:

  1. Передать данные в общий родительский компонент, а родительский компонент передает данные компоненту страницы сведений через реквизиты.
  2. Через маршрутизацию ссылка в react-router v4 может передавать параметры следующему компоненту через состояние, а следующий компонент может получать данные через this.props.location.state
  3. Используйте избыточность для управления данными

Здесь я использую второй метод

// 渲染卡片列表
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>
      )
    })
  }

Функция поиска

Как мы упоминали выше, вы можете использовать ссылку для передачи параметров для связи между компонентами.Для функции поиска здесь я использую избыточность для передачи данных между компонентами, то есть передаю значение поля ввода компоненту страницы поиска и позволяю нужно после достижения значения запросить данные из API.

  1. Сначала используйте createStore для создания контейнера хранилища, контейнер принимает редуктор чистой функции в качестве параметра для возврата нового хранилища.

const store = createStore(reducer)

  1. редуктор принимает действие и текущее состояние в качестве параметров и возвращает новое состояние
export function reducer(state = 1, action) {
switch (action.type) {
  case TRANSMIT:
    return action.data
  default:
    return state
  }
}
  1. В поле ввода есть бесчисленное множество значений значений, то есть существует бесчисленное множество видов действий, отправляемых пользователем, вы можете использовать функцию создания действий для создания действий.
export const transmit = (data) => {
  return { type: TRANSMIT, data: data }
}
  1. Здесь вводится react-redux, чтобы обернуть корневой компонент Provider, и все дочерние компоненты могут получить состояние по умолчанию.
ReactDOM.render(<Provider store={store} ><App /></Provider>, document.getElementById('root'));
  1. Используйте connect() для подключения компонентов пользовательского интерфейса Header и Search.Метод connect принимает два параметра: mapStateToProps и mapDispatchToProps. mapStateToProps подпишется на хранилище, которое будет выполнено автоматически при обновлении состояния.Компонент поиска может получить текущее состояние через this.props.keyword. mapDispatchToProps используется как объект, а каждое значение ключа в нем используется как Action Creator.
export default connect(
  state => ({keyword: state}),
  {transmit}
)(Header)

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

Поскольку у меня нет глубокого понимания редукции, процесс здесь немного громоздкий. Я просто делюсь своим пониманием. Друзья могут пойти и посмотреть на работу г-на Жуана Ифэна.учебник по редуксу, очень подробно

Любимые особенности

Любимая функция в основном реализована с помощью LocalStorage, основной идеей: при нажатии на коллекцию определить, существуют ли данные в локальной табличке, не существует, сначала используйте JSON.Stringify () в строку, чтобы сохранить локальную табличку, LocalStorage.SetItem) , Есть LocalStorage.removeItem () Collection Collection

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 = !isCollect
      localStorage.setItem(menuName, menu)
    } else {
      starColor = '#52c41a'
      isCollect = !isCollect
      localStorage.removeItem(menuName)
    }
    this.setState({
      starColor,
      isCollect
    })

    message.success((isCollect ? '收藏成功' : '取消收藏'), 1)

  }

Проект наступает на яму

antd Input.Search

Нажмите «Поиск», чтобы выполнить переход по маршруту, потому что antd инкапсулирует поле ввода и кнопку.Если вы используете ссылку для переноса поиска, вы перейдете напрямую, не вводя текст.

Решение: вместо Input.Search напрямую используйте поле ввода ввода + кнопку Button, получите значение ввода в событии нажатия кнопки, а затем оберните кнопку ссылкой для маршрутизации перехода. Это решение, о котором я подумал, если есть лучшее решение, я приглашаю друзей предложить ~

Ререндеринг страницы поиска

Включите react-redux для управления данными, используйте componentWillMount для запроса функции интерфейса API при первом отображении страницы, используйте this.props.keyword для передачи состояния в качестве параметра и используйте componentWillReceiveProps для последующей функции ловушки при поиске. и рендеринг страницы. Параметр, передаваемый в это время, — это nextProps.keyword, а не this.props.keyword.

например, реагировать на рендеринг html-кода<br />не отображается правильно

Причина: JSX-атака против инъекций React XSS превращает весь html-код в фигурных скобках в строки для рендеринга вместо html-кода

Решение: опасно использовать атрибут тега SetInnerHTML.

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

Эпилог

Портал проектов

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

Конечно, в проекте есть еще много областей для улучшения.Если вы обнаружите какие-либо ошибки или недостатки, я надеюсь, что вы можете дать мне несколько советов.

В конце концов нагло просят ЗВЕЗДУ 😋