【发布时间】:2021-02-09 04:40:27
【问题描述】:
所以我正在尝试在 react-redux 商店中设置一个计时器。我的操作正在发送到减速器,如果我从减速器中获取 console.log,我可以在控制台中看到它。
我什至在启动时间和停止计时器的按钮工作的地方连接了道具,因为我在控制台中每秒都会看到“TICK”动作。然而,我目前最大的困惑是,即使我把它挂在商店里,我似乎也看不到我的组件中呈现的值。 this.props 在 componentDidMount and render(){} 上未定义。但是,同一组件上的按钮<button onClick={this.props.startTimer}>Start</button> 会触发 startTimer 操作,因此它正在更新状态,那么为什么组件没有反映它,为什么我的 this.props 值在组件中未定义?哦,是的,只是添加我的另外两个 redux reducer/actions 工作得很好,即使他们正在使用 thunk 中间件进行 fetch/promise。欢迎任何帮助/建议,因为这是我的应用程序的最后一个障碍
代码如下:
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { Provider } from "react-redux";
import { createStore, applyMiddleware } from "redux";
import thunk from 'redux-thunk';
import reducers from './reducers'
export const store = createStore(reducers, applyMiddleware(thunk));
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
减速器
export default (state = [], action) => {
switch (action.type) {
case "FORECAST_WEATHER":
return action.payload;
default: return state;
}
};
export default (state = [], action) => {
switch (action.type) {
case "CURRENT_WEATHER":
return action.payload;
default: return state;
}
};
const START_TIMER = "START_TIMER";
const STOP_IT = "STOP_IT";
const RESUME_IT = "RESUME_IT";
const TICK = "TICK";
const initialState = {
timerOn: true,
timerStart: 0,
timerTime: 30
};
export default (state = initialState, action) => {
console.log("state is ", state);
console.log("action is ", action);
switch (action.type) {
case START_TIMER:
return {
...state,
timerOn: true,
timerTime: state.timerTime,
timerStart: Date.now() - state.timerTime,
timerId: action.timerId
};
case STOP_IT: {
return {
...state,
timerOn: false,
timerStart: 0
};
}
case TICK:
return { ...state, timerTime: state.timerTime + 1 };
default:
return state;
}
};
import { combineReducers } from "redux";
import currentWeatherReducer from './currentWeatherReducer';
import forecastReducer from './forecastReducer';
import currentTimeReducer from './currentTimeReducer';
export default combineReducers({currentWeather: currentWeatherReducer, forecast: forecastReducer, currentTime: currentTimeReducer});
动作
import { getForecast } from "../api/GET/getForecast";
import { getCurrentWeather } from "../api/GET/getCurrentWeather";
export const fetchCurrentWeather = () => async (dispatch, getState) => {
const { name, dt, main } = await getCurrentWeather();
const cityProperties = { name, dt, main };
dispatch({ type: "CURRENT_WEATHER", payload: cityProperties });
};
export const fetchForecasts = () => async (dispatch) => {
const { list } = await getForecast();
dispatch({ type: "FORECAST_WEATHER", payload: list });
};
定时器组件
import React, { useState, useEffect } from "react";
import "./Timer.scss";
import { connect } from "react-redux";
import { start, stop, tick } from "../../actions";
class Timer extends React.Component {
constructor(props) {
super(props);
}
handleStop = () => {
clearInterval(this.props.timerId);
this.props.stopTimer();
};
componentDidMount() {
console.log("TIMER PROPS IS UNDEFINED HERE", this.props);
}
render() {
const { timerTime } = this.props;
console.log("PROPS ARE ALSO UNDEFINED HERE", this.props);
return (
<div className="timer-container">
<button onClick={this.props.startTimer}>Start</button>
TIME IS: {timerTime}
<button onClick={this.handleStop}>Stop</button>
<button onClick={this.props.resetTimer}>Reset</button>
</div>
);
}
}
const mapStateToProps = (state, ownProps) => {
return {
timerOn: state.timerOn,
timerStart: state.timerStart,
timerTime: state.timerTime,
timerId: state.timerId,
};
};
const mapDispatchToProps = (dispatch) => {
console.log("dispatch", dispatch);
let timerId;
return {
startTimer: () => {
timerId = setInterval(() => dispatch({ type: "TICK" }), 1000);
dispatch({ type: "START_TIMER", timerId });
},
stopTimer: () => {
dispatch({ type: "STOP_IT" });
clearInterval(timerId);
},
resetTimer: () => dispatch({ type: "RESUME_IT" }),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Timer);
连接到商店的其他组件按预期工作
import React from "react";
import "./Header.scss";
import Timer from "../Timer";
import { connect } from "react-redux";
import { fetchCurrentWeather } from "../../actions";
class Header extends React.Component {
componentDidMount() {
this.props.fetchCurrentWeather();
console.log(this.props.currentWeather);
}
render() {
const { name, dt, temp } = this.props.currentWeather
return (
<div className="top-header">
<div className="current-city info">
<h1>{name}</h1>
<div className="time-container">
<i className="time-icon icon" >xxx</i>
<span className="time-text">{dt}</span>
<i className="time-icon icon" >xxx</i>
</div>
<span className="degrees">{temp}°</span>
</div>
<Timer />
</div>
);
}
}
const mapStateToProps = (state, ownProps) => {
return { currentWeather: state.currentWeather };
};
export default connect(mapStateToProps, { fetchCurrentWeather })(Header);
另一个连接到商店的组件可以工作
import React, { useState, useEffect } from "react";
import "./WeatherCard.scss";
import {fetchForecasts} from '../../actions';
import {connect} from 'react-redux';
class WeatherCard extends React.Component {
constructor(props) {
super(props);
}
componentDidMount(){
this.props.fetchForecasts();
console.log('PROPS IS DEFINED HERE', this.props);
}
render() {
const allRelevantData = Object.entries(this.props.forecast).map(([key, value]) => {
const dateTime = new Date(value.dt * 1000);
const day = dateTime.toString().slice(0, 3);
const item = {
day: day,
temp: Math.round(value.main.temp),
weatherMetaData: value.weather[0],
};
return item;
});
const uniqueForecasts = Array.from(
new Set(allRelevantData.map((a) => a.day))
).map((day) => {
return allRelevantData.find((a) => a.day === day);
});
return uniqueForecasts.map(({ day, temp, weatherMetaData }, index) => {
if (index < 5) {
return (
<div className="weather-card" key={index}>
<div className="day-temperature-container">
<span className="day">{day}</span>
<span className="temperature fade-in">{temp}°</span>
</div>
<div className="weather-description">
<span
className="icon weather"
style={{
background: `url(http://openweathermap.org/img/wn/${weatherMetaData.icon}.png)`,
}}
/>
<p>{weatherMetaData.description}</p>
</div>
</div>
);
}
});
}
}
const mapStateToProps = (state, ownProps) => {
return {forecast: state.forecast};
};
export default connect(mapStateToProps, {fetchForecasts})(WeatherCard);
【问题讨论】:
标签: javascript reactjs redux react-redux react-props