предисловие
Изучая 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
})
}
})
}
Затем вызовите страницу списка рендеринга данных. Здесь следует отметить, что после рендеринга предварительного изображения нажмите, чтобы перейти на страницу сведений. Как получить текущие данные для рендеринга страницы сведений?
Мне приходят в голову три идеи:
- Передать данные в общий родительский компонент, а родительский компонент передает данные компоненту страницы сведений через реквизиты.
- Через маршрутизацию ссылка в react-router v4 может передавать параметры следующему компоненту через состояние, а следующий компонент может получать данные через this.props.location.state
- Используйте избыточность для управления данными
Здесь я использую второй метод
// 渲染卡片列表
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.
- Сначала используйте createStore для создания контейнера хранилища, контейнер принимает редуктор чистой функции в качестве параметра для возврата нового хранилища.
const store = createStore(reducer)
- редуктор принимает действие и текущее состояние в качестве параметров и возвращает новое состояние
export function reducer(state = 1, action) {
switch (action.type) {
case TRANSMIT:
return action.data
default:
return state
}
}
- В поле ввода есть бесчисленное множество значений значений, то есть существует бесчисленное множество видов действий, отправляемых пользователем, вы можете использовать функцию создания действий для создания действий.
export const transmit = (data) => {
return { type: TRANSMIT, data: data }
}
- Здесь вводится react-redux, чтобы обернуть корневой компонент Provider, и все дочерние компоненты могут получить состояние по умолчанию.
ReactDOM.render(<Provider store={store} ><App /></Provider>, document.getElementById('root'));
- Используйте 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>
Эпилог
Портал проектов
При написании проекта я также столкнулся с множеством мелких проблем, которые решались одна за другой путем неспешной проверки документов.Постоянное обдумывание и решение проблем также является частью роста.
Конечно, в проекте есть еще много областей для улучшения.Если вы обнаружите какие-либо ошибки или недостатки, я надеюсь, что вы можете дать мне несколько советов.
В конце концов нагло просят ЗВЕЗДУ 😋