(反应)选择不同的下拉值不会改变任何东西
(React) Selecing different dropdown values does not change anything
我有一个下拉菜单,选择不同的值不会改变任何东西。以前,它确实改变得很好。这是我的代码:
context.js:
import React, { useState, useEffect } from 'react'
import items from './data'
const RoomContext = React.createContext()
const RoomProvider = ({ children }) => {
const [state, setState] = useState({
rooms: [],
sortedRooms: [],
featuredRooms: [],
loading: true,
type: 'all',
capacity: 1,
price: 0,
minPrice: 0,
maxPrice: 0,
minSize: 0,
maxSize: 0,
breakfast: false,
pets: false
})
const formatData = items => {
let tempItems = items.map(item => {
let id = item.sys.id
let images = item.fields.images.map(image => image.fields.file.url)
let room = { ...item.fields, images, id }
return room
})
return tempItems
}
const getRoom = slug => {
let tempRooms = [...state.rooms]
const room = tempRooms.find(room => room.slug === slug)
return room
}
useEffect(() => {
let rooms = formatData(items)
let featuredRoomsTemp = state.rooms.filter(room => room.featured)
let maxPrice = Math.max(...state.rooms.map(item => item.price))
let maxSize = Math.max(...state.rooms.map(item => item.size))
setState({
...state,
rooms,
featuredRooms: featuredRoomsTemp,
sortedRooms: rooms,
loading: false,
price: maxPrice,
maxPrice,
maxSize
})
}, [])
const handleChange = e => {
const target = e.target
const value = e.type === 'checkbox' ? target.checked : target.value
const name = e.target.name
setState({
...state,
[name]: value
})
filterRooms()
}
const filterRooms = () => {
console.log('reached')
let { rooms, type, capacity, price, minSize, maxSize, breakfast, pets } = state
let tempRooms = [...rooms]
if (type !== 'all') {
// console.log('NOT ALL')
tempRooms = tempRooms.filter(room => room.type === type)
}
console.log('temprooms:' ,tempRooms)
//ONLY AFTER ADDING THE BELOW SETSTATE, AM I UNABLE TO CHANGE THE DROPDOWN VALUES. IF I REMOVE THE BELOW, I CAN CHANGE IT JUST FINE. Why would a setState make me unable to change the values?
setState({
...state,
sortedRooms: tempRooms
})
}
return (
<RoomContext.Provider value={{
...state,
getRoom,
handleChange
}}>
{children}
</RoomContext.Provider>
)
}
const RoomConsumer = RoomContext.Consumer
export function withRoomConsumer(Component) {
return function ConsumerWrapper(props) {
return <RoomConsumer>
{value => <Component {...props} context={value} />}
</RoomConsumer>
}
}
export { RoomProvider, RoomConsumer, RoomContext }
RoomsFilter.js
import React, { useContext } from 'react'
import { RoomContext } from '../context'
import Title from './Title'
const getUnique = (items, value) => {
return [...new Set(items.map(item => item[value]))]
}
const RoomsFilter = ({ rooms }) => {
const context = useContext(RoomContext)
const { handleChange, type, capacity, price, minPrice, maxPrice, minSize, maxSize, breakfast, pets } = context
let types = getUnique(rooms, 'type')
types = ['all', ...types]
types = types.map((item, i) => {
return (
<option value={item} key={i}>{item}</option>
)
})
return (
<section className='filter-container'>
<Title title='Search rooms' />
<form className='filter-form'>
{/* select type */}
<div className='form-group'>
<label htmlFor='type'>Room type</label>
<select name='type' id='type' value={type} className='form-control' onChange={handleChange}>
{types}
</select>
</div>
{/* end select type */}
</form>
</section>
)
}
export default RoomsFilter
============================================= =====================
如你所见,只有当我添加
setState({
...state,
sortedRooms: tempRooms
})
in filterRooms (in context.js) 我无法再更改下拉值。为什么添加 setState 会这样做?
请多多指教,感谢阅读!
===============更新========= ============
- RoomsContainer 是包含下拉菜单 (RoomsFilter) 和该下拉菜单下方的房间列表 (RoomsList) 的容器。
- RoomsFilter 是下拉菜单组件
- RoomsList 是负责渲染房间的组件
房间容器:
import React from 'react'
import RoomsFilter from './RoomsFilter'
import RoomsList from './RoomsList'
import { withRoomConsumer } from '../context'
import Loading from './Loading'
function RoomContainer({ context }) {
const { loading, sortedRooms, rooms } = context
console.log(context)
if (loading) {
return <Loading />
}
return (
<div>
<RoomsFilter rooms={rooms} />
<RoomsList rooms={sortedRooms} />
</div>
)
}
export default withRoomConsumer(RoomContainer)
房间过滤器:
import React, { useContext } from 'react'
import { RoomContext } from '../context'
import Title from './Title'
const getUnique = (items, value) => {
return [...new Set(items.map(item => item[value]))]
}
const RoomsFilter = ({ rooms }) => {
const context = useContext(RoomContext)
const { handleChange, type, capacity, price, minPrice, maxPrice, minSize, maxSize, breakfast, pets } = context
let types = getUnique(rooms, 'type')
types = ['all', ...types]
types = types.map((item, i) => {
return (
<option value={item} key={i}>{item}</option>
)
})
return (
<section className='filter-container'>
<Title title='Search rooms' />
<form className='filter-form'>
{/* select type */}
<div className='form-group'>
<label htmlFor='type'>Room type</label>
<select name='type' id='type' value={type} className='form-control' onChange={handleChange}>
{types}
</select>
</div>
{/* end select type */}
</form>
</section>
)
}
export default RoomsFilter
房间列表
import React from 'react'
import Room from './Room'
const RoomsList = ({ rooms }) => {
console.log(rooms)
if (rooms.length === 0) {
return (
<div className='empty-search'>
<h3>Unfortunately no rooms match your search criteria</h3>
</div>
)
}
return (
<section className='roomslist'>
<div className='roomslist-center'>
{rooms.map(item => {
return <Room key={item.id} room={item} />
})}
</div>
</section>
)
}
export default RoomsList
您没有正确使用 setState ..应该这样使用
setState(prevState => ({...prevState , sortedRooms: tempRooms}))
问题是您有两个不同的 setState
调用;一个在您的 handleChange
函数中,另一个在 filterRooms
中。给定更改的这两个函数都使用以前的状态,但在第一个之后:
setState({
...state,
[name]: value
})
...state
在您调用时仍将具有相同的原始值:
setState({
...state,
sortedRooms: tempRooms
})
...所以第二次更新将覆盖第一次 setState
所做的。正如已经指出的那样,您可以在第二次调用中使用 setState 的回调版本,这样您就可以在第二次调用中使用 new 先前的状态:
setState(state => ({
...state,
sortedRooms: tempRooms
}));
...但是 更好的 方法是只调用 setState
一次 而不是混淆两个状态更新。而不是 filterRooms
调用 setState
,让它 return 过滤数组,并在一次调用中完成所有更新。以下是 filterRooms 可以做的事情:
const getFilteredRooms = (type) => {
let { rooms, capacity, price, minSize, maxSize, breakfast, pets } = state
return type === 'all' ? rooms : rooms.filter(room => room.type === type)
}
...并将您的 handleChange
更改为:
const handleChange = e => {
const target = e.target
const value = e.type === 'checkbox' ? target.checked : target.value
const name = e.target.name
setState({
...state,
[name]: value,
sortedRooms: getFilteredRooms(value)
})
}
我有一个下拉菜单,选择不同的值不会改变任何东西。以前,它确实改变得很好。这是我的代码:
context.js:
import React, { useState, useEffect } from 'react'
import items from './data'
const RoomContext = React.createContext()
const RoomProvider = ({ children }) => {
const [state, setState] = useState({
rooms: [],
sortedRooms: [],
featuredRooms: [],
loading: true,
type: 'all',
capacity: 1,
price: 0,
minPrice: 0,
maxPrice: 0,
minSize: 0,
maxSize: 0,
breakfast: false,
pets: false
})
const formatData = items => {
let tempItems = items.map(item => {
let id = item.sys.id
let images = item.fields.images.map(image => image.fields.file.url)
let room = { ...item.fields, images, id }
return room
})
return tempItems
}
const getRoom = slug => {
let tempRooms = [...state.rooms]
const room = tempRooms.find(room => room.slug === slug)
return room
}
useEffect(() => {
let rooms = formatData(items)
let featuredRoomsTemp = state.rooms.filter(room => room.featured)
let maxPrice = Math.max(...state.rooms.map(item => item.price))
let maxSize = Math.max(...state.rooms.map(item => item.size))
setState({
...state,
rooms,
featuredRooms: featuredRoomsTemp,
sortedRooms: rooms,
loading: false,
price: maxPrice,
maxPrice,
maxSize
})
}, [])
const handleChange = e => {
const target = e.target
const value = e.type === 'checkbox' ? target.checked : target.value
const name = e.target.name
setState({
...state,
[name]: value
})
filterRooms()
}
const filterRooms = () => {
console.log('reached')
let { rooms, type, capacity, price, minSize, maxSize, breakfast, pets } = state
let tempRooms = [...rooms]
if (type !== 'all') {
// console.log('NOT ALL')
tempRooms = tempRooms.filter(room => room.type === type)
}
console.log('temprooms:' ,tempRooms)
//ONLY AFTER ADDING THE BELOW SETSTATE, AM I UNABLE TO CHANGE THE DROPDOWN VALUES. IF I REMOVE THE BELOW, I CAN CHANGE IT JUST FINE. Why would a setState make me unable to change the values?
setState({
...state,
sortedRooms: tempRooms
})
}
return (
<RoomContext.Provider value={{
...state,
getRoom,
handleChange
}}>
{children}
</RoomContext.Provider>
)
}
const RoomConsumer = RoomContext.Consumer
export function withRoomConsumer(Component) {
return function ConsumerWrapper(props) {
return <RoomConsumer>
{value => <Component {...props} context={value} />}
</RoomConsumer>
}
}
export { RoomProvider, RoomConsumer, RoomContext }
RoomsFilter.js
import React, { useContext } from 'react'
import { RoomContext } from '../context'
import Title from './Title'
const getUnique = (items, value) => {
return [...new Set(items.map(item => item[value]))]
}
const RoomsFilter = ({ rooms }) => {
const context = useContext(RoomContext)
const { handleChange, type, capacity, price, minPrice, maxPrice, minSize, maxSize, breakfast, pets } = context
let types = getUnique(rooms, 'type')
types = ['all', ...types]
types = types.map((item, i) => {
return (
<option value={item} key={i}>{item}</option>
)
})
return (
<section className='filter-container'>
<Title title='Search rooms' />
<form className='filter-form'>
{/* select type */}
<div className='form-group'>
<label htmlFor='type'>Room type</label>
<select name='type' id='type' value={type} className='form-control' onChange={handleChange}>
{types}
</select>
</div>
{/* end select type */}
</form>
</section>
)
}
export default RoomsFilter
============================================= =====================
如你所见,只有当我添加
setState({
...state,
sortedRooms: tempRooms
})
in filterRooms (in context.js) 我无法再更改下拉值。为什么添加 setState 会这样做?
请多多指教,感谢阅读!
===============更新========= ============
- RoomsContainer 是包含下拉菜单 (RoomsFilter) 和该下拉菜单下方的房间列表 (RoomsList) 的容器。
- RoomsFilter 是下拉菜单组件
- RoomsList 是负责渲染房间的组件
房间容器:
import React from 'react'
import RoomsFilter from './RoomsFilter'
import RoomsList from './RoomsList'
import { withRoomConsumer } from '../context'
import Loading from './Loading'
function RoomContainer({ context }) {
const { loading, sortedRooms, rooms } = context
console.log(context)
if (loading) {
return <Loading />
}
return (
<div>
<RoomsFilter rooms={rooms} />
<RoomsList rooms={sortedRooms} />
</div>
)
}
export default withRoomConsumer(RoomContainer)
房间过滤器:
import React, { useContext } from 'react'
import { RoomContext } from '../context'
import Title from './Title'
const getUnique = (items, value) => {
return [...new Set(items.map(item => item[value]))]
}
const RoomsFilter = ({ rooms }) => {
const context = useContext(RoomContext)
const { handleChange, type, capacity, price, minPrice, maxPrice, minSize, maxSize, breakfast, pets } = context
let types = getUnique(rooms, 'type')
types = ['all', ...types]
types = types.map((item, i) => {
return (
<option value={item} key={i}>{item}</option>
)
})
return (
<section className='filter-container'>
<Title title='Search rooms' />
<form className='filter-form'>
{/* select type */}
<div className='form-group'>
<label htmlFor='type'>Room type</label>
<select name='type' id='type' value={type} className='form-control' onChange={handleChange}>
{types}
</select>
</div>
{/* end select type */}
</form>
</section>
)
}
export default RoomsFilter
房间列表
import React from 'react'
import Room from './Room'
const RoomsList = ({ rooms }) => {
console.log(rooms)
if (rooms.length === 0) {
return (
<div className='empty-search'>
<h3>Unfortunately no rooms match your search criteria</h3>
</div>
)
}
return (
<section className='roomslist'>
<div className='roomslist-center'>
{rooms.map(item => {
return <Room key={item.id} room={item} />
})}
</div>
</section>
)
}
export default RoomsList
您没有正确使用 setState ..应该这样使用
setState(prevState => ({...prevState , sortedRooms: tempRooms}))
问题是您有两个不同的 setState
调用;一个在您的 handleChange
函数中,另一个在 filterRooms
中。给定更改的这两个函数都使用以前的状态,但在第一个之后:
setState({
...state,
[name]: value
})
...state
在您调用时仍将具有相同的原始值:
setState({
...state,
sortedRooms: tempRooms
})
...所以第二次更新将覆盖第一次 setState
所做的。正如已经指出的那样,您可以在第二次调用中使用 setState 的回调版本,这样您就可以在第二次调用中使用 new 先前的状态:
setState(state => ({
...state,
sortedRooms: tempRooms
}));
...但是 更好的 方法是只调用 setState
一次 而不是混淆两个状态更新。而不是 filterRooms
调用 setState
,让它 return 过滤数组,并在一次调用中完成所有更新。以下是 filterRooms 可以做的事情:
const getFilteredRooms = (type) => {
let { rooms, capacity, price, minSize, maxSize, breakfast, pets } = state
return type === 'all' ? rooms : rooms.filter(room => room.type === type)
}
...并将您的 handleChange
更改为:
const handleChange = e => {
const target = e.target
const value = e.type === 'checkbox' ? target.checked : target.value
const name = e.target.name
setState({
...state,
[name]: value,
sortedRooms: getFilteredRooms(value)
})
}