Reputation: 3003
I have issue with understanding why rendering doesn't happen when render function is provided, instead of returning JSX directly.
Here's my example of InputBox component:
export default React => {
const InputBox = ({ city, setCity, setTime }) => {
const onInputEnter = createOnInputEnter({ city, setCity, setTime, getCityTime })
return (
<div className='InputBox'>
<input
defaultValue={city}
onKeyPress={onInputEnter}
onFocus={moveFocusAtEnd}
autoFocus />
</div>
)
}
return InputBox
}
in this case city is rerendered every time I change redux state of city.
export default React => {
const InputBox = ({ city, setCity, setTime }) => {
const onInputEnter = createOnInputEnter({ city, setCity, setTime, getCityTime })
const componentDidMount = async () => {
const { city: resultCity, time: resultTime } = await getCityTime(city)
setCity(resultCity)
setTime(resultTime)
}
const render = () => {
return (
<div className='InputBox'>
<input
defaultValue={city}
onKeyPress={onInputEnter}
onFocus={moveFocusAtEnd}
autoFocus />
</div>
)
}
return { render, componentDidMount }
}
return InputBox
}
In this example city is passed only once and not rerendered when redux state changes.
I would like to use latter example, since I use componentDidMount method for initialization.
I am using React and React-Redux in this example.
This is how my InputBox container looks like:
import createInputBox from '../components/InputBox.js'
import { connect } from 'react-redux'
...
export default React => {
const InputBox = createInputBox(React)
const InputBoxWithReduxStore = connect(
({ city }) => ({ city }),
mapDispatchToProps
)(InputBox)
return InputBoxWithReduxStore
}
EDIT:
I am including code snippet to show implementation of createOnInputEnter function
function createOnInputEnter ({ city, setCity, setTime, getCityTime }) {
return async ({ key, target }) => {
if (key === 'Enter') {
try {
const inputCity = target.value
setTime('...')
const { city: resultCity, time: resultTime } = await getCityTime(inputCity)
setCity(resultCity)
setTime(resultTime)
} catch (err) {
const { city: resultCity, time: resultTime } = await getCityTime(city)
setCity(resultCity)
setTime(resultTime)
}
}
}
}
As @zarcode suggested using React.Component, it does not fit my requirements. Since I use Class-less components. More on Mixin part: https://gist.github.com/jquense/47bbd2613e0b03d7e51c
Upvotes: 2
Views: 295
Reputation: 138
in first case const onInputEnter = createOnInputEnter({ city, setCity, setTime, getCityTime })
is inside the render method of the component as it is a functional component.
I am not getting how this concept work but for second example to be same as first one you will need to do something like this:
export default React => {
const InputBox = ({ city, setCity, setTime }) => {
const componentDidMount = async () => {
const { city: resultCity, time: resultTime } = await getCityTime(city)
setCity(resultCity)
setTime(resultTime)
}
const render = () => {
const { city, setCity, setTime } = this.props;
const onInputEnter = createOnInputEnter({ city, setCity, setTime, getCityTime })
return (
<div className='InputBox'>
<input
defaultValue={city}
onKeyPress={onInputEnter}
onFocus={moveFocusAtEnd}
autoFocus />
</div>
)
}
return { render, componentDidMount }
}
return InputBox
}
Although I am not sure if this is the way to access the props inside render here.
Upvotes: 0
Reputation: 2485
Your first example is a functional component, which you can use if you don't need component lifecycle methods (like componentDidMount).
Your second example is some mixture of the functional component with lifecycle methods, not sure that can work, never tried. Instead, if you want to use lifecycle methods in your component, I would suggest you use a class component that extends React.Component. It should look something like this:
...
import {Component} from "react";
export default class InputBox extends Component {
onInputEnter = () => {
const { city, setCity, setTime } = this.props;
createOnInputEnter({ city, setCity, setTime, getCityTime })
}
async componentDidMount() {
const { city, setCity, setTime } = this.props;
const { city: resultCity, time: resultTime } = await getCityTime(city)
setCity(resultCity)
setTime(resultTime)
}
render(){
return (
<div className='InputBox'>
<input
defaultValue={city}
onKeyPress={onInputEnter}
onFocus={moveFocusAtEnd}
autoFocus />
</div>
)
}
}
Upvotes: 1
Reputation:
componentDidMount will called only once and also works in the bottom-up. So for render in every state change you may use componentWillReceieveprops.
Upvotes: 1