使用API和异步存储数据构建ListView

使用API和异步存储数据构建ListView,listview,reactjs,react-native,Listview,Reactjs,React Native,要构建我的react native ListView,我需要从两个地方提取数据,一个是网络APi,另一个是异步存储(如AppCache)。异步存储中的数据可能在那里,也可能不在那里,但它需要以任何方式返回某些内容(例如“未找到”) 以下是当前版本的要点,除了检索cachedOn日期() ,我相信这就是秘密酱汁的去处 我认为这可能是任何ReactJS开发人员都可能回答的问题,尽管这个示例是ReactNative特有的 实现这一点的简单方法是通过id映射 我可以看出,您的回答为每个项目提供了唯一的i

要构建我的react native ListView,我需要从两个地方提取数据,一个是网络APi,另一个是异步存储(如AppCache)。异步存储中的数据可能在那里,也可能不在那里,但它需要以任何方式返回某些内容(例如“未找到”)

以下是当前版本的要点,除了检索cachedOn日期() ,我相信这就是秘密酱汁的去处

我认为这可能是任何ReactJS开发人员都可能回答的问题,尽管这个示例是ReactNative特有的


实现这一点的简单方法是通过
id映射

我可以看出,您的回答为每个项目提供了唯一的
id
。因此,基于相同的
id
将时间戳存储在本地存储器中。从api映射结果项时,获取项的
id
,并将其传递到本地存储的
getItem()
。这将返回该
id

const randomTime = [{
  id: 1,
  date: '05-Jun-2032 14:37:11'
}, {
  id: 2,
  date: '30-Jun-2006 00:02:27'
}, {
  id: 4,
  date: '22-Aug-1996 02:47:28'
}, {
  id: 6,
  date: '04-Jan-1991 23:27:15'
}]

const preProcessLocalStorage = () => {
  const data = JSON.parse(localStorage.getItem('date')) //read data from local storage
  const obj = {}
  data.forEach((el) => {
    obj[el.id] = el //convert into ids as keys object for better data retrieval 
  })
  return obj
}
class App extends React.Component{
  constructor(props){
    super(props)
    this.state = {
      loading: true,
    }
    this.apiData = []
    this.localData = []
    localStorage.setItem('date', JSON.stringify(randomTime)) //set Local data
  }

  componentDidMount() {
    this.localData = preProcessLocalStorage()
    $.get('https://jsonplaceholder.typicode.com/posts')
    .done((data) => {
      this.apiData = data
      this.setState({loading: false})
    })
  }

  render(){
    if(this.state.loading) return false

    const list = this.apiData.map((el) => {
      const time = this.localData[el.id] //find local data based on the api data id
      return <div>
        <h1>{el.id} - {el.title}</h1>
        <h4>{time || '-'}</h4>
      </div>
    })

    return <div>{list}</div>
  }
}

ReactDOM.render(<App/>, document.getElementById('app'))
const randomTime=[{
id:1,
日期:“2032年6月5日14:37:11”
}, {
id:2,
日期:2006年6月30日00:02:27
}, {
id:4,
日期:1996年8月22日02:47:28
}, {
id:6,
日期:1991年1月4日23:27:15
}]
const prepreprocesslocalstorage=()=>{
const data=JSON.parse(localStorage.getItem('date')//从本地存储读取数据
常量obj={}
data.forEach((el)=>{
obj[el.id]=el//将id转换为键对象以更好地检索数据
})
返回obj
}
类应用程序扩展了React.Component{
建造师(道具){
超级(道具)
此.state={
加载:对,
}
this.apiData=[]
this.localData=[]
localStorage.setItem('date',JSON.stringify(randomTime))//设置本地数据
}
componentDidMount(){
this.localData=preProcessLocalStorage()
$.get('https://jsonplaceholder.typicode.com/posts')
.完成((数据)=>{
this.apiData=数据
this.setState({loading:false})
})
}
render(){
如果(this.state.loading)返回false
const list=this.apiData.map((el)=>{
const time=this.localData[el.id]//根据api数据id查找本地数据
返回
{el.id}-{el.title}
{时间| |'-'}
})
返回{list}
}
}
ReactDOM.render(,document.getElementById('app'))

这个问题似乎相当复杂,因为存在多个级别的异步性:获取数据、读取/写入缓存以及呈现列表行。在这种情况下,将问题分解为更小的组件通常会有所帮助

我无法轻松地运行示例代码,因此我使用了一个简化的示例

首先,让我们将缓存包装成一个整洁的界面,这样在使用它时就不需要考虑
AsyncStorage
语义:

const aircraftCache={
//返回缓存飞机的承诺,如果未找到,则返回null
getAircraft(aircraftId){
返回AsyncStorage.getItem(aircraftId)。然后(数据=>(
data?JSON.parse(数据):null
));
},
//使用新的cachedOn日期缓存给定的飞机对象
//并返回缓存的飞机的承诺
setAircraft(aircraftId,aircraft){
const cached={…飞机,cachedOn:new Date()};
返回AsyncStorage.setItem(aircraftId,JSON.stringify(缓存)),然后(()=>cached);
},
//从缓存中清除给定飞机并返回承诺
clearAircraft(aircraftId){
返回AsyncStorage.removeItem(aircraftId),然后(()=>null);
}
}
然后,让我们将
AircraftList
的职责限制为仅显示数据列表、加载指示器等,并将行渲染提取到单独的组件:

class AircraftList扩展组件{
静态类型={
飞机列表:PropTypes.arrayOf(PropTypes.shape({
注册号:PropTypes.string,
ti_计数:PropTypes.number
}))
}
建造师(道具){
超级(道具);
this.ds=新的ListView.DataSource({rowHasChanged:(r1,r2)=>r1!==r2});
此.state={
数据源:this.ds.cloneWithRows(this.props.aircraft_列表),
孤岛加载:false,
showingCache:false
};
}
装载的飞机(飞机){
this.setState({isLoading:false});
这个是.props.navigator.push({
标题:“TI查找”,
组件:TrackedItemIndex,
passProps:{飞机\对象:飞机}
});
}
renderRow(飞机){
返回(
this.setState({isLoading:true})}
loaded={this.aircraftLoaded.bind(this)}
/>
);
}
render(){
//简化视图
返回(
);
}
}
然后,可以将单个行的呈现、获取和缓存操作封装到
AircraftRow
组件中:

class AircraftRow扩展组件{
静态类型={
注册号:PropTypes.string,
ti_计数:PropTypes.number,
加载:PropTypes.func,
已加载:PropTypes.func
}
状态={cachedOn:null};
建造师(道具){
超级(道具);
this.loadDetails=this.loadDetails.bind(this);
this.clearDetails=this.clearDetails.bind(this);
this.setCachedOn=this.setCachedOn.bind(this);
}
组件willmount(){
//加载组件时,查找缓存的详细信息并
//将cachedOn时间戳设置为状态
aircraftCache.getAircraft(this.props.reg_number)。然后(this.setCachedOn);
}
加载详细信息(){
const id=this.props.reg_编号;
//通知父级已开始加载
如果(本道具装载){
本.道具.装载(id);
}
//获取并缓存数据
此.fetchDetails(id)
.然后((飞机)=>{
//通知父级加载已完成
如果(此.props.loaded){
本。道具。装载(飞机);
}
})
.catch((e)=>{
控制台错误(e);
});
}
获取详细信息(id){
//从api获取详细信息,然后返回到缓存副本
返回Api.getTracketItems(id)
.然后(飞机=>a